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
35 FunctionalBlock::~FunctionalBlock() {
\r
36 if (evaluator != NULL) delete evaluator;
\r
39 void FunctionalBlock::parametersValidation(QList<AbstractBlock*>* checkedBlocks, QList<AbstractBlock *> *blocksToConfigure) {
\r
41 checkedBlocks->append(this);
\r
43 foreach(BlockParameter* param, params){
\r
44 if(param->isUserParameter() && !param->isValueSet()){
\r
45 if(!blocksToConfigure->contains(param->getOwner())){
\r
46 blocksToConfigure->append(param->getOwner());
\r
50 foreach(AbstractInterface *inter, outputs){
\r
51 foreach(AbstractInterface *connectedInter, inter->getConnectedTo()){
\r
52 if(!checkedBlocks->contains(connectedInter->getOwner())){
\r
53 connectedInter->getOwner()->parametersValidation(checkedBlocks, blocksToConfigure);
\r
60 bool FunctionalBlock::isFunctionalBlock() {
\r
64 bool FunctionalBlock::isSourceBlock() {
\r
65 if (parent == NULL) return true;
\r
69 void FunctionalBlock::populate() {
\r
72 AbstractInterface* inter;
\r
74 // create parameters from reference block
\r
75 QList<BlockParameter*> lstParam = reference->getParameters();
\r
76 for(i=0;i<lstParam.size();i++) {
\r
77 p = lstParam.at(i)->clone();
\r
81 ConnectedInterface* toClk = NULL;
\r
82 ConnectedInterface* toRst = NULL;
\r
83 // create interfaces from reference block
\r
84 QList<AbstractInterface *> lstRef = reference->getInterfaces();
\r
85 // store relation between functional and reference
\r
86 QHash<AbstractInterface *, AbstractInterface *> hashIface;
\r
87 for(i=0;i<lstRef.size();i++) {
\r
89 inter = new FunctionalInterface(this, AI_TO_REF(lstRef.at(i)));
\r
91 catch(Exception e) {
\r
92 cerr << "Abnormal case: " << qPrintable(e.getDefaultMessage()) << endl << "Aborting execution." << endl;
\r
95 hashIface.insert(lstRef.at(i),inter);
\r
96 addInterface(inter);
\r
97 /* WARNING FOR THE FUTURE :
\r
98 in case of there are several clock interfaces ofr that block
\r
99 it would be a godd idea to make the user choose which one
\r
100 must be connected to defautl clk.
\r
101 Presently, the first encountered is chosen
\r
103 if ((toClk == NULL) && (inter->getPurpose() == AbstractInterface::Clock)) {
\r
104 toClk = AI_TO_CON(inter);
\r
106 if ((toRst == NULL) && (inter->getPurpose() == AbstractInterface::Reset)) {
\r
107 toRst = AI_TO_CON(inter);
\r
111 AbstractInterface* funCtlIface = NULL;
\r
112 AbstractInterface* funDataIface = NULL;
\r
114 for(i=0;i<lstRef.size();i++) {
\r
115 AbstractInterface* refIface = lstRef.at(i);
\r
116 if (refIface->getPurpose() == AbstractInterface::Control) {
\r
117 funCtlIface = hashIface.value(refIface);
\r
118 funDataIface = hashIface.value(refIface->getAssociatedIface());
\r
119 if (! funCtlIface->setAssociatedIface(funDataIface)) {
\r
120 cerr << "Abnormal case when associating a control interface to data" << endl << "Aborting execution." << endl;
\r
126 // connect clk and rst to group clk/rst or to clkrstgen
\r
127 if ((name != "clkrstgen") && (parent != NULL)) {
\r
131 catch(Exception e) {
\r
132 AbstractBlock* source = (AbstractBlock *)(e.getSource());
\r
133 cerr << qPrintable(source->getName()) << ":" << qPrintable(e.getMessage()) << endl;
\r
139 QString FunctionalBlock::getReferenceXmlFile() {
\r
140 return ((ReferenceBlock *)reference)->getXmlFile();
\r
143 QString FunctionalBlock::getReferenceHashMd5() {
\r
144 return ((ReferenceBlock *)reference)->getHashMd5();
\r
147 void FunctionalBlock::createPatterns() throw(Exception) {
\r
148 static QString fctName = "FunctionalBlock::createPatterns()";
\r
149 #ifdef DEBUG_FCTNAME
\r
150 cout << "call to " << qPrintable(fctName) << endl;
\r
153 cout << "create patterns for block " << qPrintable(name) << endl;
\r
154 if (evaluator == NULL) evaluator = new ArithmeticEvaluator();
\r
155 if (! isGeneratorBlock()) {
\r
158 createConsumptionPattern();
\r
159 createProductionCounter();
\r
161 catch(Exception e) {
\r
162 throw(e); // rethrow e
\r
166 createProductionPattern();
\r
168 catch(Exception e) {
\r
171 cout << "PP of " << qPrintable(name) << endl;
\r
172 QMapIterator<AbstractInterface*,QList<char>* > it(productionPattern);
\r
173 while (it.hasNext()) {
\r
175 QList<char>* pat = it.value();
\r
176 foreach(char c, *pat) cout << (int)c;
\r
181 void FunctionalBlock::createDelta() throw(Exception) {
\r
182 static QString fctName = "FunctionalBlock::createDelta()";
\r
183 #ifdef DEBUG_FCTNAME
\r
184 cout << "call to " << qPrintable(fctName) << endl;
\r
187 QString deltaStr = implementation->getDelta();
\r
188 cout << "delta for " << qPrintable(name) << " = " << qPrintable(deltaStr) << endl;
\r
189 if (deltaStr.isEmpty()) {
\r
194 // look for parameter names
\r
197 result = evaluateExpression(deltaStr);
\r
199 catch(Exception e) {
\r
203 cout << "delta = " << delta << endl;
\r
206 void FunctionalBlock::createConsumptionPattern() throw(Exception) {
\r
207 static QString fctName = "FunctionalBlock::createConsumptionPattern()";
\r
208 #ifdef DEBUG_FCTNAME
\r
209 cout << "call to " << qPrintable(fctName) << endl;
\r
212 // first clear if already exists
\r
213 clearConsumptionPattern();
\r
216 QHash<QString,QString> consPattern = implementation->getConsumptionPattern();
\r
218 foreach(AbstractInterface* iface, getControlInputs()) {
\r
219 FunctionalInterface* connIface = AI_TO_FUN(iface);
\r
220 QString refName = connIface->getReference()->getName();
\r
221 if (! consPattern.contains(refName)) {
\r
222 throw(Exception(NO_IFACE_CP,this));
\r
223 cerr << "no consumption pattern for reference interface " << qPrintable(refName) << endl;
\r
225 QList<char>* pattern = NULL;
\r
227 pattern = expandPattern(consPattern.value(refName));
\r
229 catch(Exception e) {
\r
232 consumptionPattern.insert(connIface,pattern);
\r
233 if (lengthCP == -1) {
\r
234 lengthCP = pattern->size();
\r
237 if (pattern->size() != lengthCP) {
\r
238 throw(Exception(INVALID_IFACE_CP_LENGTH,this));
\r
244 void FunctionalBlock::createProductionPattern() throw(Exception){
\r
245 static QString fctName = "FunctionalBlock::createProductionPattern()";
\r
246 #ifdef DEBUG_FCTNAME
\r
247 cout << "call to " << qPrintable(fctName) << endl;
\r
250 // first clear if already exists
\r
251 clearProductionPattern();
\r
254 QHash<QString,QString> prodPattern = implementation->getProductionPattern();
\r
256 foreach(AbstractInterface* iface, getControlOutputs()) {
\r
257 FunctionalInterface* connIface = AI_TO_FUN(iface);
\r
258 QString refName = connIface->getReference()->getName();
\r
259 if (! prodPattern.contains(refName)) {
\r
260 throw(Exception(NO_IFACE_PP,this));
\r
262 QList<char>* pattern = NULL;
\r
264 pattern = expandPattern(prodPattern.value(refName));
\r
266 catch(Exception e) {
\r
269 productionPattern.insert(connIface,pattern);
\r
270 if (lengthPP == -1) {
\r
271 lengthPP = pattern->size();
\r
274 if (pattern->size() != lengthPP) {
\r
275 throw(Exception(INVALID_IFACE_PP_LENGTH,this));
\r
281 void FunctionalBlock::createProductionCounter() throw(Exception) {
\r
282 static QString fctName = "FunctionalBlock::createProductionCounter()";
\r
283 #ifdef DEBUG_FCTNAME
\r
284 cout << "call to " << qPrintable(fctName) << endl;
\r
287 // first clear if already exists
\r
288 productionCounter.clear();
\r
291 QStringList counterParts = implementation->getProductionCounter().split(",");
\r
292 foreach(QString s, counterParts) {
\r
293 cout << "cont part = " << qPrintable(s) << endl;
\r
295 double val = s.toDouble(&ok);
\r
297 productionCounter.append(val);
\r
299 else if (s.at(0) == '{') {
\r
302 QStringList gen = s.split(":");
\r
303 if (gen.size() != 3) {
\r
304 throw(Exception(INVALID_IFACE_PC,this));
\r
309 for(int i=0;i<3;i++) {
\r
310 double result = 0.0;
\r
312 result = evaluateExpression(gen.at(i));
\r
314 catch(Exception e) {
\r
317 if (i==0) start = result;
\r
318 else if (i==1) nb = result;
\r
319 else if (i==2) step = result;
\r
321 for(int j=0;j<nb;j++) {
\r
322 productionCounter.append(start+j*step);
\r
326 double result = 0.0;
\r
328 result = evaluateExpression(s);
\r
330 catch(Exception e) {
\r
333 productionCounter.append(result);
\r
336 foreach(int val, productionCounter) {
\r
337 cout << val << ",";
\r
342 QList<char>* FunctionalBlock::expandPattern(const QString& patternIn) throw(Exception) {
\r
343 static QString fctName = "FunctionalBlock::expandPattern()";
\r
344 #ifdef DEBUG_FCTNAME
\r
345 cout << "call to " << qPrintable(fctName) << endl;
\r
347 /* expanding a pattern is done in two steps :
\r
348 - 1 : finding all variables that correspond to an expression
\r
349 and copy them in the pattern
\r
350 - 2 : parsing the result
\r
352 Note that the result MUST contain only variables that have a
\r
353 integer/double value. Otherwise, expanding will fail.
\r
359 QString p = replaceExpressions(patternIn);
\r
364 QList<char>* patternOut = new QList<char>();
\r
366 patternOut->append(expandPatternRecur(p,&offset));
\r
368 catch(Exception e) {
\r
375 QString FunctionalBlock::replaceExpressions(const QString& patternIn) throw(Exception) {
\r
377 QString res = patternIn;
\r
379 QRegularExpression re("[$][a-zA-Z0-9_]+");
\r
383 QRegularExpressionMatchIterator matcher = re.globalMatch(res);
\r
384 while(matcher.hasNext()) {
\r
385 QRegularExpressionMatch m = matcher.next();
\r
386 QString param = m.captured(0);
\r
387 QString paramName = param;
\r
388 paramName.remove(0,1);
\r
389 BlockParameter* p = getParameterFromName(paramName);
\r
390 if ((p != NULL) && (p->getType() == BlockParameter::Expression)) {
\r
391 res.replace(param,p->getStringValue());
\r
393 cout << "found an expr: " << qPrintable(paramName) << ", patern => " << qPrintable(res) << endl;
\r
400 QList<char> FunctionalBlock::expandPatternRecur(const QString& patternIn, int *offset) throw(Exception) {
\r
402 QList<char> patternOut;
\r
404 while ((*offset < patternIn.size()) && (patternIn.at(*offset) != ')')) {
\r
406 QChar c = patternIn.at(*offset);
\r
410 patternOut.append(expandPatternRecur(patternIn,offset));
\r
412 catch(Exception e) {
\r
416 else if (c == '0') {
\r
417 patternOut.append(0);
\r
419 else if (c == '1') {
\r
420 patternOut.append(1);
\r
422 else if (c == 'X') {
\r
423 patternOut.append(-1);
\r
425 else if (c == '{') {
\r
427 QString expr = "";
\r
428 while ((*offset < patternIn.size()) && (patternIn.at(*offset) != '}')) {
\r
429 expr += patternIn.at(*offset);
\r
432 if (*offset == patternIn.size()) {
\r
433 throw(Exception(INVALID_IFACE_PATTERN,this));
\r
437 repeat = evaluateExpression(expr);
\r
439 catch(Exception e) {
\r
442 // repeat just the last value in currentGroup
\r
443 char last = patternOut.last();
\r
444 //cout << "repeat last char " << repeat << " times : " << (int)last << endl;
\r
446 for(int i=1;i<(int)repeat;i++) {
\r
447 patternOut.append(last);
\r
453 // must check if after ), there is a {
\r
454 if ((*offset < patternIn.size()-1) && (patternIn.at(*offset+1) == '{')) {
\r
456 QString expr = "";
\r
457 while ((*offset < patternIn.size()) && (patternIn.at(*offset) != '}')) {
\r
458 expr += patternIn.at(*offset);
\r
461 if (*offset == patternIn.size()) {
\r
462 throw(Exception(INVALID_IFACE_PATTERN,this));
\r
466 repeat = evaluateExpression(expr);
\r
468 catch(Exception e) {
\r
472 cout << "repeat last group " << repeat << " times : ";
\r
473 foreach (char c, currentGroup) cout <<(int)c;
\r
476 QList<char> single = patternOut;
\r
477 for(int i=1;i<(int)repeat;i++) {
\r
478 patternOut.append(single);
\r
484 double FunctionalBlock::evaluateExpression(const QString& expression) throw(Exception) {
\r
485 static QString fctName = "FunctionalBlock::evaluateExpression()";
\r
486 #ifdef DEBUG_FCTNAME
\r
487 cout << "call to " << qPrintable(fctName) << endl;
\r
490 QHash<QString,double> vars;
\r
491 evaluator->setExpression(expression);
\r
492 QList<QString> varNames = evaluator->getVariableNames();
\r
493 foreach (QString name, varNames) {
\r
494 QString paramName = name;
\r
495 paramName.remove(0,1);
\r
496 BlockParameter* param = getParameterFromName(paramName);
\r
497 if (param == NULL) {
\r
498 throw(Exception(EVAL_PARAM_UNKNOWN,this));
\r
501 int val = param->getDoubleValue(&okVal);
\r
503 throw(Exception(EVAL_PARAM_NOVALUE,this));
\r
505 vars.insert(name,(double)val);
\r
508 evaluator->setVariablesValue(vars);
\r
509 double result = 0.0;
\r
511 result = evaluator->evaluate();
\r
514 cerr << "Error at index " << index << ": " << qPrintable(evaluator->getError()) << endl;
\r
515 throw(Exception(EVAL_INVALID_EXPR,this));
\r
520 void FunctionalBlock::computeAdmittanceDelays() throw(Exception) {
\r
521 static QString fctName = "FunctionalBlock::computeAdmittanceDelays()";
\r
522 #ifdef DEBUG_FCTNAME
\r
523 cout << "call to " << qPrintable(fctName) << endl;
\r
525 QList<int> inClock;
\r
528 clearAdmittanceDelays();
\r
530 // trying to synchronize the first one in AP
\r
531 QMapIterator<AbstractInterface*,QList<char>* > iterAP(admittance);
\r
532 QMapIterator<AbstractInterface*,QList<char>* > iterIP(inputPattern);
\r
534 while (iterAP.hasNext()) {
\r
537 QList<char>* ap = iterAP.value();
\r
538 QList<char>* ip = iterIP.value();
\r
540 while ((first < lengthIP) && (ip->at(first) == 0)) first++;
\r
541 while ((first < lengthAP) && (ap->at(first) == 0)) first--;
\r
542 delays.append(first);
\r
544 QList<int>* delays = new QList<int>();
\r
545 admittanceDelays.insert(iterAP.key(), delays);
\r
548 QMapIterator<AbstractInterface*,QList<int>* > iterDelays(admittanceDelays);
\r
550 // get the delay to apply
\r
552 for(int i=0;i<delays.size();i++) {
\r
553 if (delays[i] > maxDelay) maxDelay = delays[i];
\r
555 // adding the delays to IP
\r
558 while (iterIP.hasNext()) {
\r
561 QList<char>* ip = iterIP.value();
\r
562 QList<int>* d = iterDelays.value();
\r
563 d->append(maxDelay-delays[i]);
\r
564 cout << "prependind " << qPrintable(iterIP.key()->getName()) << " with " << (maxDelay-delays[i]) << " 0" << endl;
\r
565 for(int j=0;j<maxDelay-delays[i];j++) {
\r
568 for(int j=0;j<delays[i];j++) {
\r
573 lengthIP += maxDelay;
\r
575 cout << "IP length = " << lengthIP << ", AP length = " << lengthAP << endl;
\r
581 // if AP is a valid group, search for the next valid group in IP
\r
582 if (isValidDataGroup(admittance,apIndex)) {
\r
584 while ((ipIndex < lengthIP) && (! isValidDataGroup(inputPattern,ipIndex))) ipIndex++;
\r
585 if (ipIndex == lengthIP) {
\r
593 iterDelays.toFront();
\r
595 if (samePatterns(inputPattern,ipIndex,admittance,apIndex)) {
\r
596 while (iterAP.hasNext()) {
\r
599 QList<char>* ap = iterAP.value();
\r
600 if (ap->at(apIndex) == 1) {
\r
601 QList<int>* d = iterDelays.value();
\r
602 d->append(0); // the 1 is at its good place, so no delay
\r
607 cout << "diff between IP and AP at " << apIndex << endl;
\r
608 // search for the next 1 in IP for every input that has a 1 in AP
\r
610 while (iterAP.hasNext()) {
\r
614 QList<char>* ap = iterAP.value();
\r
615 QList<char>* ip = iterIP.value();
\r
616 QList<int>* d = iterDelays.value();
\r
617 // case 1: 1 in IP is too late
\r
618 if ((ap->at(apIndex) == 1) && (ip->at(ipIndex) == 0)) {
\r
620 while ( ((ipIndex+delay) < lengthIP) && (ip->at(ipIndex+delay) == 0) ) delay++;
\r
621 cout << "found a delay of " << (-delay) << " for iface " << qPrintable(iterAP.key()->getName()) << endl;
\r
622 // moving the 1 to its normal pos.
\r
623 ip->replace(ipIndex,1);
\r
624 ip->replace(ipIndex+delay,0);
\r
627 // case 2: 1 in IP is too soon
\r
628 else if ((ap->at(apIndex) == 0) && (ip->at(ipIndex) == 1)) {
\r
630 while ( ((apIndex+delay) < lengthAP) && (ap->at(apIndex+delay) == 0) ) delay++;
\r
631 cout << "found a delay of " << delay << " for iface " << qPrintable(iterAP.key()->getName()) << endl;
\r
632 // search for next 0 in IP to put the 1
\r
633 int k = ipIndex+delay;
\r
634 while ((k < lengthIP) && (ip->at(k) == 1)) k++;
\r
635 ip->replace(ipIndex,0);
\r
640 if (! samePatterns(inputPattern,inClock,admittance,apIndex)) {
\r
641 cout << "Abnormal case while searching for delays" << endl;
\r
647 if ((apIndex >= lengthAP) || (ipIndex >= lengthIP)) stop = true;
\r
649 iterDelays.toFront();
\r
650 while (iterDelays.hasNext()) {
\r
652 QList<int>* d = iterDelays.value();
\r
653 foreach(int v, *d) {
\r
661 void FunctionalBlock::createInputPattern() throw(Exception) {
\r
662 static QString fctName = "FunctionalBlock::createInputPattern())";
\r
663 #ifdef DEBUG_FCTNAME
\r
664 cout << "call to " << qPrintable(fctName) << endl;
\r
668 foreach(AbstractInterface* iface, getControlInputs()) {
\r
670 ConnectedInterface* connIface = AI_TO_CON(iface);
\r
671 // check if it is connected
\r
672 if (connIface->getConnectedFrom() == NULL) {
\r
673 throw(Exception(IFACE_NOT_CONNECTED,this));
\r
675 // get the precursor output pattern
\r
676 QList<char>* out = connIface->getConnectedFrom()->getOutputPattern();
\r
677 AbstractInputModifier* modifier = connIface->getInputModifier();
\r
678 // check if the input is modified
\r
679 if (modifier != NULL) {
\r
681 out = modifier->getModifiedInput(out);
\r
684 if (out->size() == 0) {
\r
685 clearInputPattern();
\r
686 throw(Exception(NO_IFACE_IP,this));
\r
688 if (lengthIP == -1) {
\r
689 lengthIP = out->size();
\r
692 if (out->size() < lengthIP) lengthIP = out->size();
\r
695 QList<char>* in = new QList<char>(*out);
\r
696 foreach(char c, *in) {
\r
700 inputPattern.insert(connIface,in);
\r
702 // search the last valid group in IP,
\r
703 while(! isValidDataGroup(inputPattern,lengthIP-1)) {
\r
704 //removeDataGroup(inputPattern,lengthIP-1);
\r
709 void FunctionalBlock::createAdmittance(int nbExec) throw(Exception) {
\r
710 static QString fctName = "FunctionalBlock::createAdmittance()";
\r
711 #ifdef DEBUG_FCTNAME
\r
712 cout << "call to " << qPrintable(fctName) << endl;
\r
714 // firstly, copy CP in AP
\r
715 QMapIterator<AbstractInterface*,QList<char>* > iterC(consumptionPattern);
\r
716 while (iterC.hasNext()) {
\r
718 QList<char>* pattern = new QList<char>(*(iterC.value()));
\r
719 admittance.insert(iterC.key(), pattern);
\r
721 lengthAP = lengthCP;
\r
723 cout << "trigger 1 at c.c. 0" << endl;
\r
724 for(int i=1;i<nbExec;i++) {
\r
725 // searching for the clock cycle for which a new exec starts
\r
727 while ((clock < lengthAP) && (nbGroup < delta)) {
\r
728 if (isValidDataGroup(admittance,clock)) nbGroup+=1;
\r
731 while ((clock < lengthAP) && (! isValidDataGroup(admittance,clock))) clock+=1;
\r
732 cout << "trigger " << (i+1) << " at c.c. " << clock << endl;
\r
734 // combine CP with AP at sc
\r
735 for(int j=0;j<lengthCP;j++) {
\r
736 // first case : column of CP must be placed beyond AP's end.
\r
737 if (sc == lengthAP) {
\r
738 cout << i << "," << j << " append in AP at " << sc << endl;
\r
739 appendToPattern(consumptionPattern,j,admittance,1);
\r
743 // second case : CP and AP can be combined directly (i.e. no X | 1 to do)
\r
744 else if (canCombinePatterns(consumptionPattern,j,admittance,sc)) {
\r
745 cout << i << "," << j << " combine at " << sc << endl;
\r
746 combinePatterns(consumptionPattern,j,admittance,sc);
\r
749 // third case : CP has an X column
\r
750 else if (isOnlyXDataGroup(consumptionPattern,j)) {
\r
751 cout << i << "," << j << " shift rigth AP to combine at " << sc << endl;
\r
752 shiftRightPattern(admittance,sc);
\r
754 if (! canCombinePatterns(consumptionPattern,j,admittance,sc)) {
\r
755 cerr << "Abnormal case when combining AP and CP" << endl;
\r
757 combinePatterns(consumptionPattern,j,admittance,sc);
\r
760 // fourth case : AP has an X column
\r
761 else if (isOnlyXDataGroup(admittance,sc)) {
\r
762 cout << i << "," << j << " jump c.c. for CP at " << sc << endl;
\r
767 throw(INVALID_DELTA_CP);
\r
771 // turn all X into 0
\r
772 QMapIterator<AbstractInterface*,QList<char>* > iterA(admittance);
\r
773 while (iterA.hasNext()) {
\r
775 QList<char>* pattern = iterA.value();
\r
776 for(int i=0;i<pattern->size();i++) {
\r
777 if (pattern->at(i) == -1) pattern->replace(i,0);
\r
778 cout << (int)(pattern->at(i));
\r
784 void FunctionalBlock::checkInputPatternCompatibility() throw(Exception) {
\r
785 static QString fctName = "FunctionalBlock::checkInputPatternCompatibility()";
\r
786 #ifdef DEBUG_FCTNAME
\r
787 cout << "call to " << qPrintable(fctName) << endl;
\r
790 // firstly, create input pattern
\r
792 createInputPattern();
\r
794 catch(Exception e) {
\r
797 int nbExec = createTriggers();
\r
798 cout << qPrintable(name) << " will exec. " << nbExec << " times." << endl;
\r
801 createAdmittance(nbExec);
\r
803 catch(Exception e) {
\r
804 cout << "cannot create admittance" << endl;
\r
808 int clock = 0; // index in IP
\r
809 int i = 0; // index in AP
\r
810 while ((clock < lengthIP) && (i < lengthAP)) {
\r
812 // if AP is a valid group, search for the next valid group in IP
\r
813 if (isValidDataGroup(admittance,i)) {
\r
814 while ((clock < lengthIP) && (! isValidDataGroup(inputPattern,clock))) clock++;
\r
815 if (clock == lengthIP) {
\r
816 cerr << "Abnormal case: end of IP has been reached without finding a valid group" << endl;
\r
817 throw(Exception(IP_END_NULLCOL,this));
\r
820 /* at that point 2 cases of compat : IP(clock) and AP(i) are equal valid group, or
\r
821 are both null columns
\r
823 if (! samePatterns(inputPattern,clock,admittance,i)) {
\r
824 cout << "AP(" << i << ") and IP(" << clock << ") are not equal" << endl;
\r
825 throw(Exception(IP_AP_NOTCOMPAT,this)); // IP and AP not compatible
\r
830 if (clock < lengthIP) {
\r
831 throw(Exception(AP_TOO_SHORT,this));
\r
832 cerr << "Abnormal case: AP is to short" << endl;
\r
836 void FunctionalBlock::computeOutputPattern(int nbExec) throw(Exception) {
\r
837 static QString fctName = "FunctionalBlock::computeOutputPattern()";
\r
838 #ifdef DEBUG_FCTNAME
\r
839 cout << "call to " << qPrintable(fctName) << endl;
\r
842 clearOutputPattern();
\r
844 /* case 1: the block is a generator for which output pattern
\r
845 must be computed for a nbExec following executions
\r
849 cout << "computing output pattern of " << qPrintable(name) << " for " << nbExec << " executions" << endl;
\r
850 foreach(AbstractInterface* iface, getControlOutputs()) {
\r
851 FunctionalInterface* connIface = AI_TO_FUN(iface);
\r
852 // create output pattern
\r
853 QList<char>* pp = productionPattern.value(connIface);
\r
854 QList<char>* pattern = new QList<char>(*pp);
\r
855 for(int i=1;i<nbExec;i++) pattern->append(*pp);
\r
856 // assign pattern to interface
\r
857 connIface->setOutputPattern(pattern);
\r
858 // store it in QMap
\r
859 outputPattern.insert(connIface,pattern);
\r
863 cout << "computing output pattern of " << qPrintable(name) << endl;
\r
865 // in case of inputPattern not created, do it
\r
866 if (lengthIP <= 0) {
\r
868 cout << "Strange case: input pattern is not created while it is time to compute output pattern !" << endl;
\r
869 // collect the input patterns for each input
\r
871 createInputPattern();
\r
873 catch(Exception e) {
\r
876 cout << "input pattern array initialized with min. len " << lengthIP << endl;
\r
879 // initialize the output pattern
\r
881 foreach(AbstractInterface* iface, getControlOutputs()) {
\r
882 FunctionalInterface* connIface = AI_TO_FUN(iface);
\r
883 lengthOP = lengthIP+productionPattern.value(connIface)->size();
\r
884 QList<char>* pattern = new QList<char>();
\r
885 for(int i=0;i<lengthOP;i++) pattern->append(0);
\r
886 connIface->setOutputPattern(pattern);
\r
887 outputPattern.insert(connIface,pattern);
\r
889 cout << "output pattern array initialized" << endl;
\r
893 // search for the beginning of the first execution.
\r
894 while ((clock < lengthIP) && (! isValidDataGroup(inputPattern,clock))) clock++;
\r
895 cout << "found 1st exec clock: " << clock << endl;
\r
897 while (clock < lengthIP) {
\r
898 // initialize counters for current execution.
\r
899 int p = 0; // index in production pattern
\r
900 int o = 0; // clock+o will give the clock cycle of each output group
\r
901 int cip = 0; // clock+cip give the clock cycle of an input group
\r
902 int ccp = 0; // ccp give a column in the consumptio pattern
\r
903 int nip = 0; // number of input data groups already consumed during the current execution, used while exploring IP
\r
904 int ncp = 0; // number of input data groups already consumed during the current execution, used while exploring CP
\r
905 bool cannotCompleteExec = false;
\r
906 for(int m=0;m<productionCounter.size();m++) {
\r
907 // search for the first production in PP
\r
908 while (!isValidDataGroup(productionPattern,p)) {
\r
912 int gap = 0; // count the number of extra null columns
\r
913 // search for PC(m) valid input group in IP
\r
914 while (nip < productionCounter.at(m)) {
\r
915 if (clock+cip < lengthIP) {
\r
916 if (isValidDataGroup(inputPattern,clock+cip)) nip += 1;
\r
921 cannotCompleteExec = true;
\r
926 if (cannotCompleteExec) break; // no need to go further since the next search of input data group will lead to go outside inputPattern
\r
928 // search for PC(m) valid input group in IP
\r
929 while (ncp < productionCounter.at(m)) {
\r
930 if (isValidDataGroup(consumptionPattern,ccp)) ncp += 1;
\r
934 o += gap; // to take into acocunt of extra null columns
\r
935 combinePatterns(productionPattern,p,outputPattern,clock+o);
\r
940 if (cannotCompleteExec) break; // no need to go further since the next search of input data group will lead to go outside inputPattern
\r
942 // current exec. taken into accunt
\r
945 // search for the next exec.
\r
948 while ((clock < lengthIP) && (nip < delta)) {
\r
949 if (isValidDataGroup(inputPattern,clock)) nip += 1;
\r
950 if (nip < delta) clock += 1;
\r
952 cout << "found exec " << nbExec << " at clock: " << clock << endl;
\r
954 // find the last valid output data group
\r
955 while(! isValidDataGroup(outputPattern,lengthOP-1)) {
\r
956 removeDataGroup(outputPattern,lengthOP-1);
\r
960 // clear input pattern
\r
961 clearInputPattern();
\r
967 void FunctionalBlock::computeOutputPattern(int nbExec) throw(Exception) {
\r
968 static QString fctName = "FunctionalBlock::computeOutputPattern()";
\r
969 #ifdef DEBUG_FCTNAME
\r
970 cout << "call to " << qPrintable(fctName) << endl;
\r
973 // case 1: the block is a generator for which output pattern
\r
974 // must be computed for a nbExec following executions
\r
977 cout << "computing output pattern of " << qPrintable(name) << " for " << nbExec << " executions" << endl;
\r
978 foreach(AbstractInterface* iface, getControlOutputs()) {
\r
979 FunctionalInterface* connIface = AI_TO_FUN(iface);
\r
980 // create output pattern
\r
981 QList<char>* pp = productionPattern.value(connIface);
\r
982 QList<char>* pattern = new QList<char>(*pp);
\r
983 for(int i=1;i<nbExec;i++) pattern->append(*pp);
\r
984 // assign pattern to interface
\r
985 connIface->setOutputPattern(pattern);
\r
986 // store it in QMap
\r
987 outputPattern.insert(connIface,pattern);
\r
991 cout << "computing output pattern of " << qPrintable(name) << endl;
\r
993 // in case of inputPattern not created, do it
\r
994 if (lengthIP <= 0) {
\r
995 // collect the input patterns for each input
\r
997 createInputPattern();
\r
999 catch(Exception e) {
\r
1002 cout << "input pattern array initialized with min. len " << lengthIP << endl;
\r
1005 // initialize the output pattern
\r
1007 foreach(AbstractInterface* iface, getControlOutputs()) {
\r
1008 FunctionalInterface* connIface = AI_TO_FUN(iface);
\r
1009 lengthOP = lengthIP+productionPattern.value(connIface)->size();
\r
1010 QList<char>* pattern = new QList<char>();
\r
1011 for(int i=0;i<lengthOP;i++) pattern->append(0);
\r
1012 connIface->setOutputPattern(pattern);
\r
1013 outputPattern.insert(connIface,pattern);
\r
1015 cout << "output pattern array initialized" << endl;
\r
1019 // search for the beginning of the first execution.
\r
1020 while ((clock < lengthIP) && (! isValidDataGroup(inputPattern,clock))) clock++;
\r
1021 cout << "found 1st exec clock: " << clock << endl;
\r
1023 while (clock < lengthIP) {
\r
1024 // initialize counters for current execution.
\r
1025 int p = 0; // index in production pattern
\r
1026 int o = 0; // clock+o will give the clock cycle of each output group
\r
1027 int cip = 0; // clock+cip give the clock cycle of an input group
\r
1028 int ccp = 0; // ccp give a column in the consumptio pattern
\r
1029 int nip = 0; // number of input data groups already consumed during the current execution, used while exploring IP
\r
1030 int ncp = 0; // number of input data groups already consumed during the current execution, used while exploring CP
\r
1031 bool cannotCompleteExec = false;
\r
1032 for(int m=0;m<productionCounter.size();m++) {
\r
1033 // search for the first production in PP
\r
1034 while (!isValidDataGroup(productionPattern,p)) {
\r
1038 int gap = 0; // count the number of extra null columns
\r
1039 // search for PC(m) valid input group in IP
\r
1040 while (nip < productionCounter.at(m)) {
\r
1041 if (clock+cip < lengthIP) {
\r
1042 if (isValidDataGroup(inputPattern,clock+cip)) nip += 1;
\r
1047 cannotCompleteExec = true;
\r
1052 if (cannotCompleteExec) break; // no need to go further since the next search of input data group will lead to go outside inputPattern
\r
1054 // search for PC(m) valid input group in IP
\r
1055 while (ncp < productionCounter.at(m)) {
\r
1056 if (isValidDataGroup(consumptionPattern,ccp)) ncp += 1;
\r
1060 o += gap; // to take into acocunt of extra null columns
\r
1061 combinePatterns(productionPattern,p,outputPattern,clock+o);
\r
1066 if (cannotCompleteExec) break; // no need to go further since the next search of input data group will lead to go outside inputPattern
\r
1068 // current exec. taken into accunt
\r
1071 // search for the next exec.
\r
1074 while ((clock < lengthIP) && (nip < delta)) {
\r
1075 if (isValidDataGroup(inputPattern,clock)) nip += 1;
\r
1076 if (nip < delta) clock += 1;
\r
1078 cout << "found exec " << nbExec << " at clock: " << clock << endl;
\r
1080 // find the last valid output data group
\r
1081 while(! isValidDataGroup(outputPattern,lengthOP-1)) {
\r
1082 removeDataGroup(outputPattern,lengthOP-1);
\r
1086 // clear input pattern
\r
1087 clearInputPattern();
\r
1091 bool FunctionalBlock::samePatterns(const QMap<AbstractInterface*, QList<char>* >& patternSrc, int srcCol, const QMap<AbstractInterface*, QList<char>* >& patternDest, int destCol) {
\r
1093 if (patternSrc.size() != patternDest.size()) return false;
\r
1094 QMapIterator<AbstractInterface*, QList<char>* > iterSrc(patternSrc);
\r
1095 QMapIterator<AbstractInterface*, QList<char>* > iterDest(patternDest);
\r
1096 while (iterSrc.hasNext()) {
\r
1099 QList<char>* srcPat = iterSrc.value();
\r
1100 QList<char>* destPat = iterDest.value();
\r
1101 if (srcCol >= srcPat->size()) return false;
\r
1102 if (destCol >= destPat->size()) return false;
\r
1103 if (srcPat->at(srcCol) != destPat->at(destCol)) return false;
\r
1108 bool FunctionalBlock::samePatterns(const QMap<AbstractInterface*, QList<char>* >& patternSrc, const QList<int> &srcCols, const QMap<AbstractInterface*, QList<char>* >& patternDest, int destCol) {
\r
1109 if (patternSrc.size() != srcCols.size()) return false;
\r
1110 if (patternSrc.size() != patternDest.size()) return false;
\r
1112 QMapIterator<AbstractInterface*, QList<char>* > iterSrc(patternSrc);
\r
1113 QListIterator<int> iterSrcCol(srcCols);
\r
1114 QMapIterator<AbstractInterface*, QList<char>* > iterDest(patternDest);
\r
1115 while (iterSrc.hasNext()) {
\r
1117 int srcCol = iterSrcCol.next();
\r
1119 QList<char>* srcPat = iterSrc.value();
\r
1120 QList<char>* destPat = iterDest.value();
\r
1121 if (srcCol >= srcPat->size()) return false;
\r
1122 if (destCol >= destPat->size()) return false;
\r
1123 if (srcPat->at(srcCol) != destPat->at(destCol)) return false;
\r
1128 bool FunctionalBlock::canCombinePatterns(const QMap<AbstractInterface*, QList<char>* >& patternSrc, int srcCol, QMap<AbstractInterface*, QList<char>* > patternDest, int destCol) {
\r
1129 if (patternSrc.size() != patternDest.size()) return false;
\r
1130 QMapIterator<AbstractInterface*, QList<char>* > iterSrc(patternSrc);
\r
1131 QMapIterator<AbstractInterface*, QList<char>* > iterDest(patternDest);
\r
1132 while (iterSrc.hasNext()) {
\r
1135 QList<char>* srcPat = iterSrc.value();
\r
1136 QList<char>* destPat = iterDest.value();
\r
1137 if (srcCol >= srcPat->size()) return false;
\r
1138 if (destCol >= destPat->size()) return false;
\r
1139 if ((srcPat->at(srcCol) == -1) && (destPat->at(destCol) == 1)) return false;
\r
1140 if ((srcPat->at(srcCol) == 1) && (destPat->at(destCol) == -1)) return false;
\r
1145 void FunctionalBlock::combinePatterns(const QMap<AbstractInterface*, QList<char>* >& patternSrc, int srcCol, QMap<AbstractInterface*, QList<char>* > patternDest, int destCol) {
\r
1146 if (patternSrc.size() != patternDest.size()) return;
\r
1147 QMapIterator<AbstractInterface*, QList<char>* > iterSrc(patternSrc);
\r
1148 QMapIterator<AbstractInterface*, QList<char>* > iterDest(patternDest);
\r
1149 while (iterSrc.hasNext()) {
\r
1152 QList<char>* srcPat = iterSrc.value();
\r
1153 QList<char>* destPat = iterDest.value();
\r
1154 if (srcCol >= srcPat->size()) return;
\r
1155 if (destCol >= destPat->size()) return;
\r
1156 if ((srcPat->at(srcCol) == -1) && (destPat->at(destCol) == 1)) return;
\r
1157 if ((srcPat->at(srcCol) == 1) && (destPat->at(destCol) == -1)) return;
\r
1158 destPat->replace(destCol,destPat->at(destCol) | srcPat->at(srcCol));
\r
1162 void FunctionalBlock::appendToPattern(const QMap<AbstractInterface*, QList<char>* >& patternSrc, int srcCol, QMap<AbstractInterface*, QList<char>* > patternDest, int nbCols) {
\r
1163 if (patternSrc.size() != patternDest.size()) return;
\r
1164 QMapIterator<AbstractInterface*, QList<char>* > iterSrc(patternSrc);
\r
1165 QMapIterator<AbstractInterface*, QList<char>* > iterDest(patternDest);
\r
1166 while (iterSrc.hasNext()) {
\r
1169 QList<char>* srcPat = iterSrc.value();
\r
1170 QList<char>* destPat = iterDest.value();
\r
1172 while ((srcCol+i < srcPat->size()) && (i<nbCols)) {
\r
1173 destPat->append(srcPat->at(srcCol+i));
\r
1179 void FunctionalBlock::removeDataGroup(QMap<AbstractInterface *, QList<char> *> &pattern, int offset) {
\r
1180 QMapIterator<AbstractInterface*, QList<char>* > iterSrc(pattern);
\r
1181 while (iterSrc.hasNext()) {
\r
1183 QList<char>* srcPat = iterSrc.value();
\r
1184 if (offset < srcPat->size()) {
\r
1185 srcPat->removeAt(offset);
\r
1190 void FunctionalBlock::shiftRightPattern(const QMap<AbstractInterface *, QList<char> *> &pattern, int offset) {
\r
1191 QMapIterator<AbstractInterface*, QList<char>* > iterSrc(pattern);
\r
1192 while (iterSrc.hasNext()) {
\r
1194 QList<char>* srcPat = iterSrc.value();
\r
1195 if (offset < srcPat->size()) {
\r
1196 srcPat->insert(offset,0);
\r
1201 bool FunctionalBlock::isValidDataGroup(const QMap<AbstractInterface *, QList<char> *> &pattern, int offset) {
\r
1202 QMapIterator<AbstractInterface*, QList<char>* > iterSrc(pattern);
\r
1203 while (iterSrc.hasNext()) {
\r
1205 QList<char>* srcPat = iterSrc.value();
\r
1206 if (offset >= srcPat->size()) return false;
\r
1207 if (srcPat->at(offset) == 1) return true;
\r
1212 bool FunctionalBlock::isValidDataGroup(const QMap<AbstractInterface*, QList<char>* >& pattern, const QList<int> offsets) {
\r
1213 QMapIterator<AbstractInterface*, QList<char>* > iterSrc(pattern);
\r
1214 QListIterator<int> iterOffsets(offsets);
\r
1215 while (iterSrc.hasNext()) {
\r
1217 int offset = iterOffsets.next();
\r
1218 QList<char>* srcPat = iterSrc.value();
\r
1219 if (offset >= srcPat->size()) return false;
\r
1220 if (srcPat->at(offset) == 1) return true;
\r
1225 bool FunctionalBlock::isOnlyXDataGroup(const QMap<AbstractInterface *, QList<char> *> &pattern, int offset) {
\r
1226 QMapIterator<AbstractInterface*, QList<char>* > iterSrc(pattern);
\r
1227 while (iterSrc.hasNext()) {
\r
1229 QList<char>* srcPat = iterSrc.value();
\r
1230 if (offset >= srcPat->size()) return false;
\r
1231 if (srcPat->at(offset) != -1) return false;
\r
1236 void FunctionalBlock::clearConsumptionPattern() {
\r
1237 QMapIterator<AbstractInterface*, QList<char>* > iterP(consumptionPattern);
\r
1238 while (iterP.hasNext()) {
\r
1240 QList<char>* pattern = iterP.value();
\r
1241 if (pattern != NULL) delete pattern;
\r
1243 consumptionPattern.clear();
\r
1247 void FunctionalBlock::clearProductionPattern() {
\r
1248 QMapIterator<AbstractInterface*, QList<char>* > iterP(productionPattern);
\r
1249 while (iterP.hasNext()) {
\r
1251 QList<char>* pattern = iterP.value();
\r
1252 if (pattern != NULL) delete pattern;
\r
1254 productionPattern.clear();
\r
1258 void FunctionalBlock::clearInputPattern() {
\r
1260 QMapIterator<AbstractInterface*,QList<char>* > iterI(inputPattern);
\r
1261 while (iterI.hasNext()) {
\r
1263 QList<char>* pattern = iterI.value();
\r
1264 if (pattern != NULL) delete pattern;
\r
1266 inputPattern.clear();
\r
1270 void FunctionalBlock::clearOutputPattern() {
\r
1272 QMapIterator<AbstractInterface*,QList<char>* > iterO(outputPattern);
\r
1273 while (iterO.hasNext()) {
\r
1275 ConnectedInterface* connIface = AI_TO_CON(iterO.key());
\r
1276 connIface->resetOutputPattern();
\r
1277 QList<char>* pattern = iterO.value();
\r
1278 if (pattern != NULL) delete pattern;
\r
1280 outputPattern.clear();
\r
1284 void FunctionalBlock::clearAdmittanceDelays() {
\r
1285 QMapIterator<AbstractInterface*, QList<int>* > iterA(admittanceDelays);
\r
1286 while (iterA.hasNext()) {
\r
1288 QList<int>* d = iterA.value();
\r
1289 if (d != NULL) delete d;
\r
1291 admittanceDelays.clear();
\r
1294 int FunctionalBlock::createTriggers() {
\r
1296 /* NB: this method returns the number of executions that have been started
\r
1297 but not necessary completed.
\r
1299 if (delta <= 0) return 0;
\r
1301 // search for the first exec.
\r
1302 while ((offset < lengthIP) && (! isValidDataGroup(inputPattern,offset))) offset++;
\r
1303 if (offset == lengthIP) return 0;
\r
1304 triggers.append(offset);
\r
1306 for(int i = offset;i<lengthIP;i++) {
\r
1307 if (isValidDataGroup(inputPattern,i)) nbGroup++;
\r
1308 if (nbGroup == delta+1) {
\r
1309 triggers.append(i);
\r
1313 return triggers.size();
\r