]> AND Private Git Repository - blast.git/blob - FunctionalBlock.cpp
Logo AND Algorithmique Numérique Distribuée

Private GIT Repository
modif in VHDLConverter
[blast.git] / FunctionalBlock.cpp
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
9 \r
10 \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
15   parent = _parent;\r
16   name = reference->getName();\r
17 \r
18   if (reference->getImplementations().isEmpty()) {\r
19     implementation = NULL;\r
20     cout << "block has no implementation" << endl;\r
21   }\r
22   else {\r
23     implementation = reference->getImplementations().at(0);\r
24   }\r
25   lengthAP = -1;\r
26   lengthCP = -1;\r
27   lengthIP = -1;\r
28   lengthOP = -1;\r
29   lengthPP = -1;\r
30   delta = -1;\r
31   evaluator = NULL;\r
32 }\r
33 \r
34 FunctionalBlock::~FunctionalBlock() {\r
35   if (evaluator != NULL) delete evaluator;\r
36 }\r
37 \r
38 void FunctionalBlock::parametersValidation(QList<AbstractBlock*>* checkedBlocks, QList<AbstractBlock *> *blocksToConfigure) {\r
39   /*\r
40   checkedBlocks->append(this);\r
41 \r
42   foreach(BlockParameter* param, params){\r
43     if(param->isUserParameter() && !param->isValueSet()){\r
44       if(!blocksToConfigure->contains(param->getOwner())){\r
45         blocksToConfigure->append(param->getOwner());\r
46       }\r
47     }\r
48   }\r
49   foreach(AbstractInterface *inter, outputs){\r
50     foreach(AbstractInterface *connectedInter, inter->getConnectedTo()){\r
51       if(!checkedBlocks->contains(connectedInter->getOwner())){\r
52         connectedInter->getOwner()->parametersValidation(checkedBlocks, blocksToConfigure);\r
53       }\r
54     }\r
55   }\r
56   */\r
57 }\r
58 \r
59 bool FunctionalBlock::isFunctionalBlock() {\r
60   return true;\r
61 }\r
62 \r
63 bool FunctionalBlock::isSourceBlock() {\r
64   if (parent == NULL) return true;\r
65   return false;\r
66 }\r
67 \r
68 void FunctionalBlock::populate() {\r
69   int i;\r
70   BlockParameter* p;\r
71   AbstractInterface* inter;\r
72 \r
73   // create parameters from reference block\r
74   QList<BlockParameter*> lstParam = reference->getParameters();\r
75   for(i=0;i<lstParam.size();i++) {\r
76     p = lstParam.at(i)->clone();\r
77     addParameter(p);\r
78   }\r
79 \r
80   // create interfaces from reference block\r
81   QList<AbstractInterface *> lstRef = reference->getInterfaces();\r
82   // store relation between functional and reference\r
83   QHash<AbstractInterface *, AbstractInterface *> hashIface;\r
84   for(i=0;i<lstRef.size();i++) {\r
85     try {\r
86       inter = new FunctionalInterface(this, AI_TO_REF(lstRef.at(i)));\r
87     }\r
88     catch(Exception e) {\r
89       cerr << "Abnormal case: " << qPrintable(e.getDefaultMessage()) << endl << "Aborting execution." << endl;\r
90       exit(1);\r
91     }\r
92     hashIface.insert(lstRef.at(i),inter);\r
93 \r
94     addInterface(inter);\r
95   }\r
96     \r
97   AbstractInterface* funCtlIface = NULL;\r
98   AbstractInterface* funDataIface = NULL;\r
99   \r
100   for(i=0;i<lstRef.size();i++) {    \r
101     AbstractInterface* refIface = lstRef.at(i);    \r
102     if (refIface->getPurpose() == AbstractInterface::Control) {\r
103       funCtlIface = hashIface.value(refIface);\r
104       funDataIface = hashIface.value(refIface->getAssociatedIface());\r
105       if (! funCtlIface->setAssociatedIface(funDataIface)) {\r
106         cerr << "Abnormal case when associating a control interface to data" << endl << "Aborting execution." << endl;\r
107         exit(1);\r
108       }       \r
109     }\r
110   }\r
111 }\r
112 \r
113 \r
114 QString FunctionalBlock::getReferenceXmlFile() {\r
115     return ((ReferenceBlock *)reference)->getXmlFile();\r
116 }\r
117 \r
118 QString FunctionalBlock::getReferenceHashMd5() {\r
119     return ((ReferenceBlock *)reference)->getHashMd5();\r
120 }\r
121 \r
122 void FunctionalBlock::createPatterns() throw(Exception) {\r
123   static QString fctName = "FunctionalBlock::createPatterns()";\r
124 #ifdef DEBUG_FCTNAME\r
125   cout << "call to " << qPrintable(fctName) << endl;\r
126 #endif\r
127   \r
128   cout << "create patterns for block " << qPrintable(name) << endl;\r
129   if (evaluator == NULL) evaluator = new ArithmeticEvaluator();\r
130   if (! isGeneratorBlock()) {\r
131     try {\r
132       createDelta();\r
133       createConsumptionPattern();    \r
134       createProductionCounter();\r
135     }\r
136     catch(Exception e) {\r
137       throw(e); // rethrow e\r
138     }\r
139   }\r
140   try {\r
141     createProductionPattern();\r
142   }\r
143   catch(Exception e) {\r
144     throw(e);\r
145   }\r
146   cout << "PP of " << qPrintable(name) << endl;\r
147   QMapIterator<AbstractInterface*,QList<char>* > it(productionPattern);\r
148   while (it.hasNext()) {\r
149     it.next();\r
150     QList<char>* pat = it.value();\r
151     foreach(char c, *pat) cout << (int)c;\r
152     cout << endl;\r
153   }\r
154 }\r
155 \r
156 void FunctionalBlock::createDelta() throw(Exception) {\r
157   static QString fctName = "FunctionalBlock::createDelta()";\r
158 #ifdef DEBUG_FCTNAME\r
159   cout << "call to " << qPrintable(fctName) << endl;\r
160 #endif \r
161   \r
162   QString deltaStr = implementation->getDelta();  \r
163   cout << "delta for " << qPrintable(name) << " = " << qPrintable(deltaStr) << endl;\r
164   if (deltaStr.isEmpty()) {\r
165     delta = -1;\r
166     return;\r
167   }\r
168   \r
169   // look for parameter names  \r
170   double result = 0;\r
171   try {\r
172     result = evaluateExpression(deltaStr);\r
173   }\r
174   catch(Exception e) {\r
175     throw(e);\r
176   }\r
177   delta = result;\r
178   cout << "delta = " << delta << endl;\r
179 }\r
180 \r
181 void FunctionalBlock::createConsumptionPattern()  throw(Exception) {\r
182   static QString fctName = "FunctionalBlock::createConsumptionPattern()";\r
183 #ifdef DEBUG_FCTNAME\r
184   cout << "call to " << qPrintable(fctName) << endl;\r
185 #endif\r
186   \r
187   lengthCP = -1;  \r
188   QHash<QString,QString> consPattern = implementation->getConsumptionPattern();  \r
189   \r
190   foreach(AbstractInterface* iface, getControlInputs()) {       \r
191     FunctionalInterface* connIface = AI_TO_FUN(iface);\r
192     QString refName = connIface->getReference()->getName();    \r
193     if (! consPattern.contains(refName)) {\r
194       throw(Exception(NO_IFACE_CP));\r
195       cerr << "no consumption pattern for reference interface " << qPrintable(refName) << endl;\r
196     }\r
197     QList<char>* pattern = NULL;\r
198     try {\r
199       pattern = expandPattern(consPattern.value(refName));\r
200     }\r
201     catch(Exception e) {\r
202       throw(e);\r
203     }\r
204     consumptionPattern.insert(connIface,pattern);\r
205     if (lengthCP == -1) {\r
206       lengthCP = pattern->size();\r
207     }\r
208     else {\r
209       if (pattern->size() != lengthCP) {\r
210         throw(Exception(INVALID_IFACE_CP_LENGTH));\r
211       }\r
212     }\r
213   }          \r
214 }\r
215 \r
216 void FunctionalBlock::createProductionPattern() throw(Exception){  \r
217   static QString fctName = "FunctionalBlock::createProductionPattern()";\r
218 #ifdef DEBUG_FCTNAME\r
219   cout << "call to " << qPrintable(fctName) << endl;\r
220 #endif\r
221   \r
222   lengthPP = -1;  \r
223   QHash<QString,QString> prodPattern = implementation->getProductionPattern();  \r
224   \r
225   foreach(AbstractInterface* iface, getControlOutputs()) {    \r
226     FunctionalInterface* connIface = AI_TO_FUN(iface);\r
227     QString refName = connIface->getReference()->getName();    \r
228     if (! prodPattern.contains(refName)) {\r
229       throw(Exception(NO_IFACE_PP));      \r
230     }\r
231     QList<char>* pattern = NULL;\r
232     try {\r
233       pattern = expandPattern(prodPattern.value(refName));\r
234     }\r
235     catch(Exception e) {\r
236       throw(e);\r
237     }\r
238     productionPattern.insert(connIface,pattern);\r
239     if (lengthPP == -1) {\r
240       lengthPP = pattern->size();\r
241     }\r
242     else {\r
243       if (pattern->size() != lengthPP) {\r
244         throw(Exception(INVALID_IFACE_PP_LENGTH));\r
245       }\r
246     }\r
247   }      \r
248 }\r
249 \r
250 void FunctionalBlock::createProductionCounter() throw(Exception) {\r
251   static QString fctName = "FunctionalBlock::createProductionCounter()";\r
252 #ifdef DEBUG_FCTNAME\r
253   cout << "call to " << qPrintable(fctName) << endl;\r
254 #endif\r
255   \r
256   QStringList counterParts = implementation->getProductionCounter().split(",");\r
257   foreach(QString s, counterParts) {\r
258     cout << "cont part = " << qPrintable(s) << endl;\r
259     bool ok;\r
260     double val = s.toDouble(&ok);\r
261     if (ok) {\r
262       productionCounter.append(val);\r
263     }\r
264     else if (s.at(0) == '{') {\r
265       s.remove(0,1);\r
266       s.chop(1);\r
267       QStringList gen = s.split(":");\r
268       if (gen.size() != 3) {\r
269         throw(Exception(INVALID_IFACE_PC));\r
270       }\r
271       int start = 0;\r
272       int nb = 0;\r
273       int step = 0;\r
274       for(int i=0;i<3;i++) {        \r
275         double result = 0.0;\r
276         try {\r
277           result = evaluateExpression(gen.at(i));\r
278         }\r
279         catch(Exception e) {\r
280           throw(e);\r
281         }\r
282         if (i==0) start = result;\r
283         else if (i==1) nb = result;\r
284         else if (i==2) step = result;\r
285       }\r
286       for(int j=0;j<nb;j++) {\r
287         productionCounter.append(start+j*step);\r
288       }\r
289     }\r
290     else {      \r
291       double result = 0.0;\r
292       try {\r
293         result = evaluateExpression(s);\r
294       }\r
295       catch(Exception e) {\r
296         throw(e);\r
297       }\r
298       productionCounter.append(result);      \r
299     }\r
300   }\r
301   foreach(int val, productionCounter) {\r
302     cout << val << ",";\r
303   }\r
304   cout << endl;\r
305 }\r
306 \r
307 QList<char>* FunctionalBlock::expandPattern(const QString& patternIn) throw(Exception) {\r
308   static QString fctName = "FunctionalBlock::expandPattern()";\r
309 #ifdef DEBUG_FCTNAME\r
310   cout << "call to " << qPrintable(fctName) << endl;\r
311 #endif\r
312   \r
313   QList<char> lst;\r
314   QString  p = patternIn;\r
315   p.append(')');\r
316   int offset = 0;  \r
317   QList<char>* patternOut = new QList<char>();\r
318   try {\r
319     patternOut->append(expandPatternRecur(p,&offset));\r
320   }\r
321   catch(Exception e) {\r
322     throw(e);\r
323   }\r
324 \r
325   return patternOut;\r
326 }\r
327 \r
328 QList<char> FunctionalBlock::expandPatternRecur(const QString& patternIn, int *offset) throw(Exception) {\r
329   \r
330   QList<char> patternOut;\r
331 \r
332   while ((*offset < patternIn.size()) && (patternIn.at(*offset) != ')')) {\r
333     \r
334     QChar c = patternIn.at(*offset);\r
335     if (c == '(') {\r
336       *offset += 1;\r
337       try {\r
338         patternOut.append(expandPatternRecur(patternIn,offset));\r
339       }\r
340       catch(Exception e) {\r
341         throw(e);\r
342       }\r
343     }\r
344     else if (c == '0') {\r
345       patternOut.append(0);\r
346     }\r
347     else if (c == '1') {\r
348       patternOut.append(1);\r
349     }\r
350     else if (c == 'X') {\r
351       patternOut.append(-1);\r
352     }\r
353     else if (c == '{') {\r
354       *offset += 1;\r
355       QString expr = "";      \r
356       while ((*offset < patternIn.size()) && (patternIn.at(*offset) != '}')) {\r
357         expr += patternIn.at(*offset);        \r
358         *offset += 1;\r
359       }\r
360       if (*offset == patternIn.size()) {\r
361         throw(Exception(INVALID_IFACE_PATTERN));\r
362       }\r
363       double repeat = 0;\r
364       try {\r
365         repeat = evaluateExpression(expr);\r
366       }\r
367       catch(Exception e) {\r
368         throw(e);\r
369       }\r
370       // repeat just the last value in currentGroup\r
371       char last = patternOut.last();\r
372       //cout << "repeat last char " << repeat << " times : " << (int)last << endl;\r
373       \r
374       for(int i=1;i<(int)repeat;i++) {\r
375         patternOut.append(last);\r
376       }\r
377     }    \r
378     *offset += 1;\r
379   }\r
380   \r
381   // must check if after ), there is a {\r
382   if ((*offset < patternIn.size()-1) && (patternIn.at(*offset+1) == '{')) {\r
383     *offset += 2;\r
384     QString expr = "";      \r
385     while ((*offset < patternIn.size()) && (patternIn.at(*offset) != '}')) {\r
386       expr += patternIn.at(*offset);        \r
387       *offset += 1;\r
388     }\r
389     if (*offset == patternIn.size()) {\r
390       throw(Exception(INVALID_IFACE_PATTERN));\r
391     }\r
392     double repeat = 0;\r
393     try {\r
394       repeat = evaluateExpression(expr);\r
395     }\r
396     catch(Exception e) {\r
397       throw(e);\r
398     }\r
399     /*\r
400     cout << "repeat last group " << repeat << " times : ";\r
401     foreach (char c, currentGroup) cout <<(int)c;\r
402     cout << endl;  \r
403     */\r
404     QList<char> single = patternOut;\r
405     for(int i=1;i<(int)repeat;i++) {\r
406       patternOut.append(single);\r
407     }    \r
408   }  \r
409   return patternOut;\r
410 }\r
411 \r
412 double FunctionalBlock::evaluateExpression(const QString& expression) throw(Exception) {\r
413   static QString fctName = "FunctionalBlock::evaluateExpression()";\r
414 #ifdef DEBUG_FCTNAME\r
415   cout << "call to " << qPrintable(fctName) << endl;\r
416 #endif\r
417     \r
418   QHash<QString,double> vars;\r
419   evaluator->setExpression(expression);\r
420   QList<QString> varNames = evaluator->getVariableNames();\r
421   foreach (QString name, varNames) {\r
422     QString paramName = name;\r
423     paramName.remove(0,1);\r
424     BlockParameter* param = reference->getParameterFromName(paramName);    \r
425     if (param == NULL) {\r
426       throw(Exception(EVAL_PARAM_UNKNOWN));\r
427     }\r
428     bool okVal;\r
429     int val = param->getDoubleValue(&okVal);\r
430     if (!okVal) {\r
431       throw(Exception(EVAL_PARAM_NOVALUE));      \r
432     }\r
433     vars.insert(name,(double)val);    \r
434   }\r
435   \r
436   evaluator->setVariablesValue(vars);\r
437   double result = 0.0;\r
438   try {\r
439     result = evaluator->evaluate();\r
440   }\r
441   catch(int index) {\r
442     cerr << "Error at index " << index << ": " << qPrintable(evaluator->getError()) << endl;\r
443     throw(Exception(EVAL_INVALID_EXPR));\r
444   }\r
445   return result;\r
446 }\r
447 \r
448 void FunctionalBlock::createInputPattern()  throw(Exception) {\r
449   static QString fctName = "FunctionalBlock::createInputPattern())";\r
450 #ifdef DEBUG_FCTNAME\r
451   cout << "call to " << qPrintable(fctName) << endl;\r
452 #endif\r
453   \r
454   lengthIP = -1;\r
455   foreach(AbstractInterface* iface, getControlInputs()) {      \r
456     ConnectedInterface* connIface = AI_TO_CON(iface);\r
457     QList<char>* out = connIface->getConnectedFrom()->getOutputPattern();\r
458     if (out->size() == 0) {\r
459       clearInputPattern();\r
460       throw(Exception(NO_IFACE_IP));\r
461     }\r
462     if (lengthIP == -1) {\r
463       lengthIP = out->size();\r
464     }\r
465     else {\r
466       if (out->size() < lengthIP) lengthIP = out->size();\r
467     }\r
468     \r
469     QList<char>* in = new QList<char>(*out);\r
470     foreach(char c, *in) {\r
471       cout << (int)c;\r
472     }\r
473     cout << endl;    \r
474     inputPattern.insert(connIface,in);    \r
475   }\r
476   // search the last valid group in IP,\r
477   while(! isValidDataGroup(inputPattern,lengthIP-1)) {\r
478     //removeDataGroup(inputPattern,lengthIP-1);\r
479     lengthIP -= 1;\r
480   }\r
481 }\r
482 \r
483 void FunctionalBlock::createAdmittance(int nbExec) throw(Exception) {\r
484   static QString fctName = "FunctionalBlock::createAdmittance()";\r
485 #ifdef DEBUG_FCTNAME\r
486   cout << "call to " << qPrintable(fctName) << endl;\r
487 #endif  \r
488   // firstly, copy CP in AP\r
489   QMapIterator<AbstractInterface*,QList<char>* > iterC(consumptionPattern);\r
490   while (iterC.hasNext()) {\r
491     iterC.next();\r
492     QList<char>* pattern = new QList<char>(*(iterC.value()));\r
493     admittance.insert(iterC.key(), pattern);    \r
494   }\r
495   lengthAP = lengthCP;\r
496   int clock = 0;  \r
497   cout << "trigger 1 at c.c. 0" << endl;\r
498   for(int i=1;i<nbExec;i++) {\r
499     // searching for the clock cycle for which a new exec starts\r
500     int nbGroup = 0;\r
501     while ((clock < lengthAP) && (nbGroup < delta)) {\r
502       if (isValidDataGroup(admittance,clock)) nbGroup+=1;\r
503       clock += 1;\r
504     }\r
505     while ((clock < lengthAP) && (! isValidDataGroup(admittance,clock))) clock+=1;\r
506     cout << "trigger " << (i+1) << " at c.c. " << clock << endl;\r
507     int sc = clock;\r
508     // combine CP with AP at sc\r
509     for(int j=0;j<lengthCP;j++) {\r
510       // first case : column of CP must be placed beyond AP's end.\r
511       if (sc == lengthAP) {\r
512         cout << i << "," << j << " append in AP at " << sc << endl;\r
513         appendToPattern(consumptionPattern,j,admittance,1);\r
514         lengthAP += 1;\r
515         sc += 1;               \r
516       }\r
517       // second case : CP and AP can be combined directly (i.e. no X | 1 to do)\r
518       else if (canCombinePatterns(consumptionPattern,j,admittance,sc)) {\r
519         cout << i << "," << j << " combine at " << sc << endl;\r
520         combinePatterns(consumptionPattern,j,admittance,sc);\r
521         sc += 1;\r
522       }\r
523       // third case : CP has an X column\r
524       else if (isOnlyXDataGroup(consumptionPattern,j)) {\r
525         cout << i << "," << j << " shift rigth AP to combine at " << sc << endl;\r
526         shiftRightPattern(admittance,sc);\r
527         lengthAP += 1;\r
528         if (! canCombinePatterns(consumptionPattern,j,admittance,sc)) {\r
529           cerr << "Abnormal case when combining AP and CP" << endl;\r
530         }\r
531         combinePatterns(consumptionPattern,j,admittance,sc);        \r
532         sc += 1;\r
533       }\r
534       // fourth case : AP has an X column\r
535       else if (isOnlyXDataGroup(admittance,sc)) {\r
536         cout << i << "," << j << " jump c.c. for CP at " << sc << endl;        \r
537         sc += 1;\r
538         j -= 1;\r
539       }\r
540       else {\r
541         throw(INVALID_DELTA_CP);        \r
542       }\r
543     }\r
544   }\r
545   // turn all X into 0\r
546   QMapIterator<AbstractInterface*,QList<char>* > iterA(admittance);\r
547   while (iterA.hasNext()) {\r
548     iterA.next();\r
549     QList<char>* pattern = iterA.value();\r
550     for(int i=0;i<pattern->size();i++) {\r
551       if (pattern->at(i) == -1) pattern->replace(i,0);\r
552       cout << (int)(pattern->at(i));\r
553     }\r
554     cout << endl;\r
555   }  \r
556 }\r
557 \r
558 void FunctionalBlock::checkInputPatternCompatibility() throw(Exception) {\r
559   static QString fctName = "FunctionalBlock::checkInputPatternCompatibility()";\r
560 #ifdef DEBUG_FCTNAME\r
561   cout << "call to " << qPrintable(fctName) << endl;\r
562 #endif\r
563     \r
564   // firstly, create input pattern\r
565   try {\r
566     createInputPattern();\r
567   }\r
568   catch(Exception e) {\r
569     throw(e);\r
570   }\r
571   int nbExec = createTriggers();\r
572   cout << qPrintable(name) << " will exec. " << nbExec << " times." << endl;\r
573   \r
574   try {\r
575     createAdmittance(nbExec);\r
576   }\r
577   catch(Exception e) {\r
578     cout << "cannot create admittance" << endl;\r
579     throw(e);\r
580   }\r
581   \r
582   int clock = 0; // index in IP  \r
583   int i = 0; // index in AP  \r
584   while ((clock < lengthIP) && (i < lengthAP)) {\r
585      \r
586     // if AP is a valid group, search for the next valid group in IP\r
587     if (isValidDataGroup(admittance,i)) {\r
588       while ((clock < lengthIP) && (! isValidDataGroup(inputPattern,clock))) clock++;\r
589       if (clock == lengthIP) {\r
590         cerr << "Abnormal case: end of IP has been reached without finding a valid group" << endl;\r
591         throw(Exception(IP_END_NULLCOL));        \r
592       }\r
593     }    \r
594     /* at that point 2 cases of compat : IP(clock) and AP(i) are equal valid group, or\r
595        are both null columns\r
596     */\r
597     if (! samePatterns(inputPattern,clock,admittance,i)) {\r
598       cout << "AP(" << i << ") and IP(" << clock << ") are not equal" << endl;\r
599       throw(Exception(IP_AP_NOTCOMPAT)); // IP and AP not compatible\r
600     }\r
601     clock++;\r
602     i++;\r
603   }\r
604   if (clock < lengthIP) {\r
605     throw(Exception(AP_TOO_SHORT));\r
606     cerr << "Abnormal case: AP is to short" << endl;   \r
607   }  \r
608 }\r
609 \r
610 void FunctionalBlock::computeOutputPattern(int nbExec) throw(Exception) {\r
611   static QString fctName = "FunctionalBlock::computeOutputPattern()";\r
612 #ifdef DEBUG_FCTNAME\r
613   cout << "call to " << qPrintable(fctName) << endl;\r
614 #endif\r
615   \r
616   /* case 1: the block is a generator for which output pattern\r
617      must be computed for a nbExec following executions\r
618   */\r
619   \r
620   \r
621   if (nbExec > 0) {\r
622     cout << "computing output pattern of " << qPrintable(name) << " for " << nbExec << " executions" << endl;\r
623     foreach(AbstractInterface* iface, getControlOutputs()) {\r
624       FunctionalInterface* connIface = AI_TO_FUN(iface);\r
625       // create output pattern\r
626       QList<char>* pp = productionPattern.value(connIface);\r
627       QList<char>* pattern = new QList<char>(*pp);\r
628       for(int i=1;i<nbExec;i++) pattern->append(*pp);\r
629       // assign pattern to interface\r
630       connIface->setOutputPattern(pattern);\r
631       // store it in QMap\r
632       outputPattern.insert(connIface,pattern);      \r
633     }\r
634   }\r
635   else {\r
636     cout << "computing output pattern of " << qPrintable(name) << endl;\r
637     \r
638     // in case of inputPattern not created, do it\r
639     if (lengthIP <= 0) {\r
640       // collect the input patterns for each input    \r
641       try {\r
642         createInputPattern();\r
643       }\r
644       catch(Exception e) {\r
645         throw(e);\r
646       }\r
647       cout << "input pattern array initialized with min. len " << lengthIP << endl;\r
648     }\r
649     \r
650     // initialize the output pattern    \r
651     lengthOP = 0;\r
652     foreach(AbstractInterface* iface, getControlOutputs()) {\r
653       FunctionalInterface* connIface = AI_TO_FUN(iface);      \r
654       lengthOP = lengthIP+productionPattern.value(connIface)->size();\r
655       QList<char>* pattern = new QList<char>();\r
656       for(int i=0;i<lengthOP;i++) pattern->append(0);\r
657       connIface->setOutputPattern(pattern);\r
658       outputPattern.insert(connIface,pattern);\r
659     }\r
660     cout << "output pattern array initialized" << endl;\r
661     \r
662     int clock = 0;\r
663     nbExec = 0;\r
664     // search for the beginning of the first execution.\r
665     while ((clock < lengthIP) && (! isValidDataGroup(inputPattern,clock))) clock++;\r
666     cout << "found 1st exec clock: " << clock << endl;\r
667     \r
668     while (clock < lengthIP) {\r
669       // initialize counters for current execution.\r
670       int p = 0; // index in production pattern\r
671       int o = 0; // clock+o will give the clock cycle of each output group\r
672       int cip = 0; // clock+cip give the clock cycle of an input group\r
673       int ccp = 0; // ccp give a column in the consumptio pattern\r
674       int nip = 0; // number of input data groups already consumed during the current execution, used while exploring IP\r
675       int ncp = 0; // number of input data groups already consumed during the current execution, used while exploring CP\r
676       bool cannotCompleteExec = false;\r
677       for(int m=0;m<productionCounter.size();m++) {\r
678         // search for the first production in PP\r
679         while (!isValidDataGroup(productionPattern,p)) {\r
680           p += 1;\r
681           o += 1;\r
682         }\r
683         int gap = 0; // count the number of extra null columns\r
684         // search for PC(m) valid input group in IP\r
685         while (nip < productionCounter.at(m)) {\r
686           if (clock+cip < lengthIP) {\r
687             if (isValidDataGroup(inputPattern,clock+cip)) nip += 1;\r
688             cip += 1;\r
689             gap += 1;\r
690           }\r
691           else {\r
692             cannotCompleteExec = true;\r
693             break;\r
694           }        \r
695         }        \r
696         \r
697         if (cannotCompleteExec) break; // no need to go further since the next search of input data group will lead to go outside inputPattern\r
698         \r
699         // search for PC(m) valid input group in IP\r
700         while (ncp < productionCounter.at(m)) {\r
701           if (isValidDataGroup(consumptionPattern,ccp)) ncp += 1;\r
702           ccp += 1;\r
703           gap -= 1;\r
704         }\r
705         o += gap; // to take into acocunt of extra null columns\r
706         combinePatterns(productionPattern,p,outputPattern,clock+o);\r
707         p += 1;\r
708         o += 1;\r
709       }\r
710       \r
711       if (cannotCompleteExec) break; // no need to go further since the next search of input data group will lead to go outside inputPattern\r
712       \r
713       // current exec. taken into accunt\r
714       nbExec += 1;\r
715       \r
716       // search for the next exec.\r
717       clock += 1;      \r
718       nip = 0;\r
719       while ((clock < lengthIP) && (nip < delta)) {\r
720         if (isValidDataGroup(inputPattern,clock)) nip += 1;\r
721         if (nip < delta) clock += 1;\r
722       }\r
723       cout << "found exec " << nbExec << " at clock: " << clock << endl;\r
724     }\r
725     // find the last valid output data group\r
726     while(! isValidDataGroup(outputPattern,lengthOP-1)) {\r
727       removeDataGroup(outputPattern,lengthOP-1);\r
728       lengthOP -= 1;\r
729     }\r
730 \r
731     // clear input pattern\r
732     clearInputPattern();\r
733   }  \r
734 }\r
735 \r
736 /*\r
737 \r
738 void FunctionalBlock::computeOutputPattern(int nbExec) throw(Exception) {\r
739   static QString fctName = "FunctionalBlock::computeOutputPattern()";\r
740 #ifdef DEBUG_FCTNAME\r
741   cout << "call to " << qPrintable(fctName) << endl;\r
742 #endif\r
743 \r
744   // case 1: the block is a generator for which output pattern\r
745   //   must be computed for a nbExec following executions\r
746 \r
747   if (nbExec > 0) {\r
748     cout << "computing output pattern of " << qPrintable(name) << " for " << nbExec << " executions" << endl;\r
749     foreach(AbstractInterface* iface, getControlOutputs()) {\r
750       FunctionalInterface* connIface = AI_TO_FUN(iface);\r
751       // create output pattern\r
752       QList<char>* pp = productionPattern.value(connIface);\r
753       QList<char>* pattern = new QList<char>(*pp);\r
754       for(int i=1;i<nbExec;i++) pattern->append(*pp);\r
755       // assign pattern to interface\r
756       connIface->setOutputPattern(pattern);\r
757       // store it in QMap\r
758       outputPattern.insert(connIface,pattern);\r
759     }\r
760   }\r
761   else {\r
762     cout << "computing output pattern of " << qPrintable(name) << endl;\r
763 \r
764     // in case of inputPattern not created, do it\r
765     if (lengthIP <= 0) {\r
766       // collect the input patterns for each input\r
767       try {\r
768         createInputPattern();\r
769       }\r
770       catch(Exception e) {\r
771         throw(e);\r
772       }\r
773       cout << "input pattern array initialized with min. len " << lengthIP << endl;\r
774     }\r
775 \r
776     // initialize the output pattern\r
777     lengthOP = 0;\r
778     foreach(AbstractInterface* iface, getControlOutputs()) {\r
779       FunctionalInterface* connIface = AI_TO_FUN(iface);\r
780       lengthOP = lengthIP+productionPattern.value(connIface)->size();\r
781       QList<char>* pattern = new QList<char>();\r
782       for(int i=0;i<lengthOP;i++) pattern->append(0);\r
783       connIface->setOutputPattern(pattern);\r
784       outputPattern.insert(connIface,pattern);\r
785     }\r
786     cout << "output pattern array initialized" << endl;\r
787 \r
788     int clock = 0;\r
789     nbExec = 0;\r
790     // search for the beginning of the first execution.\r
791     while ((clock < lengthIP) && (! isValidDataGroup(inputPattern,clock))) clock++;\r
792     cout << "found 1st exec clock: " << clock << endl;\r
793 \r
794     while (clock < lengthIP) {\r
795       // initialize counters for current execution.\r
796       int p = 0; // index in production pattern\r
797       int o = 0; // clock+o will give the clock cycle of each output group\r
798       int cip = 0; // clock+cip give the clock cycle of an input group\r
799       int ccp = 0; // ccp give a column in the consumptio pattern\r
800       int nip = 0; // number of input data groups already consumed during the current execution, used while exploring IP\r
801       int ncp = 0; // number of input data groups already consumed during the current execution, used while exploring CP\r
802       bool cannotCompleteExec = false;\r
803       for(int m=0;m<productionCounter.size();m++) {\r
804         // search for the first production in PP\r
805         while (!isValidDataGroup(productionPattern,p)) {\r
806           p += 1;\r
807           o += 1;\r
808         }\r
809         int gap = 0; // count the number of extra null columns\r
810         // search for PC(m) valid input group in IP\r
811         while (nip < productionCounter.at(m)) {\r
812           if (clock+cip < lengthIP) {\r
813             if (isValidDataGroup(inputPattern,clock+cip)) nip += 1;\r
814             cip += 1;\r
815             gap += 1;\r
816           }\r
817           else {\r
818             cannotCompleteExec = true;\r
819             break;\r
820           }\r
821         }\r
822 \r
823         if (cannotCompleteExec) break; // no need to go further since the next search of input data group will lead to go outside inputPattern\r
824 \r
825         // search for PC(m) valid input group in IP\r
826         while (ncp < productionCounter.at(m)) {\r
827           if (isValidDataGroup(consumptionPattern,ccp)) ncp += 1;\r
828           ccp += 1;\r
829           gap -= 1;\r
830         }\r
831         o += gap; // to take into acocunt of extra null columns\r
832         combinePatterns(productionPattern,p,outputPattern,clock+o);\r
833         p += 1;\r
834         o += 1;\r
835       }\r
836 \r
837       if (cannotCompleteExec) break; // no need to go further since the next search of input data group will lead to go outside inputPattern\r
838 \r
839       // current exec. taken into accunt\r
840       nbExec += 1;\r
841 \r
842       // search for the next exec.\r
843       clock += 1;\r
844       nip = 0;\r
845       while ((clock < lengthIP) && (nip < delta)) {\r
846         if (isValidDataGroup(inputPattern,clock)) nip += 1;\r
847         if (nip < delta) clock += 1;\r
848       }\r
849       cout << "found exec " << nbExec << " at clock: " << clock << endl;\r
850     }\r
851     // find the last valid output data group\r
852     while(! isValidDataGroup(outputPattern,lengthOP-1)) {\r
853       removeDataGroup(outputPattern,lengthOP-1);\r
854       lengthOP -= 1;\r
855     }\r
856 \r
857     // clear input pattern\r
858     clearInputPattern();\r
859   }\r
860 }\r
861 */\r
862 bool FunctionalBlock::samePatterns(const QMap<AbstractInterface*, QList<char>* >& patternSrc, int srcCol, const QMap<AbstractInterface*, QList<char>* >& patternDest, int destCol) {\r
863   \r
864   if (patternSrc.size() != patternDest.size()) return false;\r
865   QMapIterator<AbstractInterface*, QList<char>* > iterSrc(patternSrc);\r
866   QMapIterator<AbstractInterface*, QList<char>* > iterDest(patternDest);\r
867   while (iterSrc.hasNext()) {\r
868     iterSrc.next();\r
869     iterDest.next();    \r
870     QList<char>* srcPat = iterSrc.value();\r
871     QList<char>* destPat = iterDest.value();\r
872     if (srcCol >= srcPat->size()) return false;\r
873     if (destCol >= destPat->size()) return false;\r
874     if (srcPat->at(srcCol) != destPat->at(destCol)) return false;    \r
875   }\r
876   return true;\r
877 }\r
878 \r
879 bool FunctionalBlock::canCombinePatterns(const QMap<AbstractInterface*, QList<char>* >& patternSrc, int srcCol, QMap<AbstractInterface*, QList<char>* > patternDest, int destCol) {\r
880   if (patternSrc.size() != patternDest.size()) return false;\r
881   QMapIterator<AbstractInterface*, QList<char>* > iterSrc(patternSrc);\r
882   QMapIterator<AbstractInterface*, QList<char>* > iterDest(patternDest);\r
883   while (iterSrc.hasNext()) {\r
884     iterSrc.next();\r
885     iterDest.next();    \r
886     QList<char>* srcPat = iterSrc.value();\r
887     QList<char>* destPat = iterDest.value();\r
888     if (srcCol >= srcPat->size()) return false;\r
889     if (destCol >= destPat->size()) return false;\r
890     if ((srcPat->at(srcCol) == -1) && (destPat->at(destCol) == 1)) return false;\r
891     if ((srcPat->at(srcCol) == 1) && (destPat->at(destCol) == -1)) return false;\r
892   }\r
893   return true;\r
894 }\r
895 \r
896 void FunctionalBlock::combinePatterns(const QMap<AbstractInterface*, QList<char>* >& patternSrc, int srcCol, QMap<AbstractInterface*, QList<char>* > patternDest, int destCol) {\r
897   if (patternSrc.size() != patternDest.size()) return;\r
898   QMapIterator<AbstractInterface*, QList<char>* > iterSrc(patternSrc);\r
899   QMapIterator<AbstractInterface*, QList<char>* > iterDest(patternDest);\r
900   while (iterSrc.hasNext()) {\r
901     iterSrc.next();\r
902     iterDest.next();    \r
903     QList<char>* srcPat = iterSrc.value();\r
904     QList<char>* destPat = iterDest.value();\r
905     if (srcCol >= srcPat->size()) return;\r
906     if (destCol >= destPat->size()) return;\r
907     if ((srcPat->at(srcCol) == -1) && (destPat->at(destCol) == 1)) return;\r
908     if ((srcPat->at(srcCol) == 1) && (destPat->at(destCol) == -1)) return;    \r
909     destPat->replace(destCol,destPat->at(destCol) | srcPat->at(srcCol));\r
910   }  \r
911 }\r
912 \r
913 void FunctionalBlock::appendToPattern(const QMap<AbstractInterface*, QList<char>* >& patternSrc, int srcCol, QMap<AbstractInterface*, QList<char>* > patternDest, int nbCols) {\r
914   if (patternSrc.size() != patternDest.size()) return;\r
915   QMapIterator<AbstractInterface*, QList<char>* > iterSrc(patternSrc);\r
916   QMapIterator<AbstractInterface*, QList<char>* > iterDest(patternDest);\r
917   while (iterSrc.hasNext()) {\r
918     iterSrc.next();\r
919     iterDest.next();    \r
920     QList<char>* srcPat = iterSrc.value();\r
921     QList<char>* destPat = iterDest.value();    \r
922     int i=0;\r
923     while ((srcCol+i < srcPat->size()) && (i<nbCols)) {\r
924       destPat->append(srcPat->at(srcCol+i));\r
925       i++;\r
926     }\r
927   }  \r
928 }\r
929 \r
930 void FunctionalBlock::removeDataGroup(QMap<AbstractInterface *, QList<char> *> &pattern, int offset) {\r
931   QMapIterator<AbstractInterface*, QList<char>* > iterSrc(pattern);  \r
932   while (iterSrc.hasNext()) {\r
933     iterSrc.next();    \r
934     QList<char>* srcPat = iterSrc.value();\r
935     if (offset < srcPat->size()) {\r
936       srcPat->removeAt(offset);\r
937     }\r
938   }\r
939 }\r
940 \r
941 void FunctionalBlock::shiftRightPattern(const QMap<AbstractInterface *, QList<char> *> &pattern, int offset) {\r
942   QMapIterator<AbstractInterface*, QList<char>* > iterSrc(pattern);  \r
943   while (iterSrc.hasNext()) {\r
944     iterSrc.next();    \r
945     QList<char>* srcPat = iterSrc.value();\r
946     if (offset < srcPat->size()) {\r
947       srcPat->insert(offset,0);\r
948     }\r
949   }\r
950 }\r
951 \r
952 bool FunctionalBlock::isValidDataGroup(const QMap<AbstractInterface *, QList<char> *> &pattern, int offset) {\r
953   QMapIterator<AbstractInterface*, QList<char>* > iterSrc(pattern);  \r
954   while (iterSrc.hasNext()) {\r
955     iterSrc.next();    \r
956     QList<char>* srcPat = iterSrc.value();\r
957     if (offset >= srcPat->size()) return false;\r
958     if (srcPat->at(offset) == 1) return true;\r
959   }\r
960   return false;\r
961 }\r
962 \r
963 bool FunctionalBlock::isOnlyXDataGroup(const QMap<AbstractInterface *, QList<char> *> &pattern, int offset) {\r
964   QMapIterator<AbstractInterface*, QList<char>* > iterSrc(pattern);  \r
965   while (iterSrc.hasNext()) {\r
966     iterSrc.next();    \r
967     QList<char>* srcPat = iterSrc.value();\r
968     if (offset >= srcPat->size()) return false;\r
969     if (srcPat->at(offset) != -1) return false;\r
970   }\r
971   return true;  \r
972 }\r
973 \r
974 void FunctionalBlock::clearConsumptionPattern() {\r
975   QMapIterator<AbstractInterface*, QList<char>* > iterP(consumptionPattern);  \r
976   while (iterP.hasNext()) {\r
977     iterP.next();\r
978     QList<char>* pattern = iterP.value();\r
979     if (pattern != NULL) delete pattern;\r
980   }\r
981   consumptionPattern.clear();\r
982   lengthCP = -1;      \r
983 }  \r
984 \r
985 void FunctionalBlock::clearProductionPattern() {\r
986   QMapIterator<AbstractInterface*, QList<char>* > iterP(productionPattern);  \r
987   while (iterP.hasNext()) {\r
988     iterP.next();\r
989     QList<char>* pattern = iterP.value();\r
990     if (pattern != NULL) delete pattern;\r
991   }\r
992   productionPattern.clear();\r
993   lengthPP = -1;\r
994 }  \r
995 \r
996 void FunctionalBlock::clearInputPattern() {\r
997   \r
998   QMapIterator<AbstractInterface*,QList<char>* > iterI(inputPattern);\r
999   while (iterI.hasNext()) {\r
1000     iterI.next();\r
1001     QList<char>* pattern = iterI.value();\r
1002     if (pattern != NULL) delete pattern;\r
1003   }\r
1004   inputPattern.clear();\r
1005   lengthIP = -1;\r
1006 }\r
1007 \r
1008 int FunctionalBlock::createTriggers() {\r
1009   triggers.clear();\r
1010   /* NB: this method returns the number of executions that have been started\r
1011      but not necessary completed.\r
1012   */\r
1013   if (delta <= 0) return 0;  \r
1014   int offset = 0;\r
1015   // search for the first exec.\r
1016   while ((offset < lengthIP) && (! isValidDataGroup(inputPattern,offset))) offset++;\r
1017   if (offset == lengthIP) return 0;\r
1018   triggers.append(offset);  \r
1019   int nbGroup = 0;\r
1020   for(int i = offset;i<lengthIP;i++) {\r
1021     if (isValidDataGroup(inputPattern,i)) nbGroup++;\r
1022     if (nbGroup == delta+1) {\r
1023       triggers.append(i);\r
1024       nbGroup = 1;\r
1025     }\r
1026   }      \r
1027   return triggers.size();\r
1028 }\r