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, bool createIfaces) 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
39 FunctionalBlock::~FunctionalBlock() {
\r
40 if (evaluator != NULL) delete evaluator;
\r
43 void FunctionalBlock::parametersValidation(QList<AbstractBlock*>* checkedBlocks, QList<AbstractBlock *> *blocksToConfigure) {
\r
45 checkedBlocks->append(this);
\r
47 foreach(BlockParameter* param, params){
\r
48 if(param->isUserParameter() && !param->isValueSet()){
\r
49 if(!blocksToConfigure->contains(param->getOwner())){
\r
50 blocksToConfigure->append(param->getOwner());
\r
54 foreach(AbstractInterface *inter, outputs){
\r
55 foreach(AbstractInterface *connectedInter, inter->getConnectedTo()){
\r
56 if(!checkedBlocks->contains(connectedInter->getOwner())){
\r
57 connectedInter->getOwner()->parametersValidation(checkedBlocks, blocksToConfigure);
\r
64 bool FunctionalBlock::isFunctionalBlock() {
\r
68 bool FunctionalBlock::isSourceBlock() {
\r
69 if (parent == NULL) return true;
\r
73 void FunctionalBlock::populate() {
\r
76 AbstractInterface* inter;
\r
78 // create parameters from reference block
\r
79 QList<BlockParameter*> lstParam = reference->getParameters();
\r
80 for(i=0;i<lstParam.size();i++) {
\r
81 p = lstParam.at(i)->clone();
\r
85 ConnectedInterface* toClk = NULL;
\r
86 ConnectedInterface* toRst = NULL;
\r
87 // create interfaces from reference block
\r
88 QList<AbstractInterface *> lstRef = reference->getInterfaces();
\r
89 // store relation between functional and reference
\r
90 QHash<AbstractInterface *, AbstractInterface *> hashIface;
\r
91 for(i=0;i<lstRef.size();i++) {
\r
93 inter = new FunctionalInterface(this, AI_TO_REF(lstRef.at(i)));
\r
95 catch(Exception e) {
\r
96 cerr << "Abnormal case: " << qPrintable(e.getDefaultMessage()) << endl << "Aborting execution." << endl;
\r
99 hashIface.insert(lstRef.at(i),inter);
\r
100 addInterface(inter);
\r
101 /* WARNING FOR THE FUTURE :
\r
102 in case of there are several clock interfaces ofr that block
\r
103 it would be a good idea to make the user choose which one
\r
104 must be connected to defautl clk.
\r
105 Presently, the first encountered is chosen
\r
107 if ((toClk == NULL) && (inter->getPurpose() == AbstractInterface::Clock)) {
\r
108 toClk = AI_TO_CON(inter);
\r
110 if ((toRst == NULL) && (inter->getPurpose() == AbstractInterface::Reset)) {
\r
111 toRst = AI_TO_CON(inter);
\r
115 AbstractInterface* funCtlIface = NULL;
\r
116 AbstractInterface* funDataIface = NULL;
\r
118 for(i=0;i<lstRef.size();i++) {
\r
119 AbstractInterface* refIface = lstRef.at(i);
\r
120 if (refIface->getPurpose() == AbstractInterface::Control) {
\r
121 funCtlIface = hashIface.value(refIface);
\r
122 funDataIface = hashIface.value(refIface->getAssociatedIface());
\r
123 if (! funCtlIface->setAssociatedIface(funDataIface)) {
\r
124 cerr << "Abnormal case when associating a control interface to data" << endl << "Aborting execution." << endl;
\r
131 QString FunctionalBlock::getReferenceXmlFile() {
\r
132 return ((ReferenceBlock *)reference)->getXmlFile();
\r
135 QString FunctionalBlock::getReferenceHashMd5() {
\r
136 return ((ReferenceBlock *)reference)->getHashMd5();
\r
139 void FunctionalBlock::createPatterns() throw(Exception) {
\r
140 static QString fctName = "FunctionalBlock::createPatterns()";
\r
141 #ifdef DEBUG_FCTNAME
\r
142 cout << "call to " << qPrintable(fctName) << endl;
\r
145 if (implementation->hasNoPatterns()) return;
\r
147 cout << "create patterns for block " << qPrintable(name) << endl;
\r
148 if (evaluator == NULL) evaluator = new ArithmeticEvaluator();
\r
149 if (! isGeneratorBlock()) {
\r
152 createConsumptionPattern();
\r
153 createProductionCounter();
\r
155 catch(Exception e) {
\r
156 throw(e); // rethrow e
\r
160 createProductionPattern();
\r
162 catch(Exception e) {
\r
165 cout << "PP of " << qPrintable(name) << endl;
\r
166 QMapIterator<AbstractInterface*,QList<char>* > it(productionPattern);
\r
167 while (it.hasNext()) {
\r
169 QList<char>* pat = it.value();
\r
170 foreach(char c, *pat) cout << (int)c;
\r
175 void FunctionalBlock::createDelta() throw(Exception) {
\r
176 static QString fctName = "FunctionalBlock::createDelta()";
\r
177 #ifdef DEBUG_FCTNAME
\r
178 cout << "call to " << qPrintable(fctName) << endl;
\r
181 QString deltaStr = implementation->getDelta();
\r
182 cout << "delta for " << qPrintable(name) << " = " << qPrintable(deltaStr) << endl;
\r
183 if (deltaStr.isEmpty()) {
\r
188 // look for parameter names
\r
191 result = evaluateExpression(deltaStr);
\r
193 catch(Exception e) {
\r
197 cout << "delta = " << delta << endl;
\r
200 void FunctionalBlock::createConsumptionPattern() throw(Exception) {
\r
201 static QString fctName = "FunctionalBlock::createConsumptionPattern()";
\r
202 #ifdef DEBUG_FCTNAME
\r
203 cout << "call to " << qPrintable(fctName) << endl;
\r
206 // first clear if already exists
\r
207 clearConsumptionPattern();
\r
210 QHash<QString,QString> consPattern = implementation->getConsumptionPattern();
\r
212 foreach(AbstractInterface* iface, getControlInputs()) {
\r
213 FunctionalInterface* connIface = AI_TO_FUN(iface);
\r
214 QString refName = connIface->getReference()->getName();
\r
215 if (! consPattern.contains(refName)) {
\r
216 throw(Exception(NO_IFACE_CP,this));
\r
217 cerr << "no consumption pattern for reference interface " << qPrintable(refName) << endl;
\r
219 QList<char>* pattern = NULL;
\r
221 pattern = expandPattern(consPattern.value(refName));
\r
223 catch(Exception e) {
\r
226 consumptionPattern.insert(connIface,pattern);
\r
227 if (lengthCP == -1) {
\r
228 lengthCP = pattern->size();
\r
231 if (pattern->size() != lengthCP) {
\r
232 throw(Exception(INVALID_IFACE_CP_LENGTH,this));
\r
238 void FunctionalBlock::createProductionPattern() throw(Exception){
\r
239 static QString fctName = "FunctionalBlock::createProductionPattern()";
\r
240 #ifdef DEBUG_FCTNAME
\r
241 cout << "call to " << qPrintable(fctName) << endl;
\r
244 // first clear if already exists
\r
245 clearProductionPattern();
\r
248 QHash<QString,QString> prodPattern = implementation->getProductionPattern();
\r
250 foreach(AbstractInterface* iface, getControlOutputs()) {
\r
251 FunctionalInterface* connIface = AI_TO_FUN(iface);
\r
252 QString refName = connIface->getReference()->getName();
\r
253 if (! prodPattern.contains(refName)) {
\r
254 throw(Exception(NO_IFACE_PP,this));
\r
256 QList<char>* pattern = NULL;
\r
258 pattern = expandPattern(prodPattern.value(refName));
\r
260 catch(Exception e) {
\r
263 productionPattern.insert(connIface,pattern);
\r
264 if (lengthPP == -1) {
\r
265 lengthPP = pattern->size();
\r
268 if (pattern->size() != lengthPP) {
\r
269 throw(Exception(INVALID_IFACE_PP_LENGTH,this));
\r
275 void FunctionalBlock::createProductionCounter() throw(Exception) {
\r
276 static QString fctName = "FunctionalBlock::createProductionCounter()";
\r
277 #ifdef DEBUG_FCTNAME
\r
278 cout << "call to " << qPrintable(fctName) << endl;
\r
281 // first clear if already exists
\r
282 productionCounter.clear();
\r
285 QStringList counterParts = implementation->getProductionCounter().split(",");
\r
286 foreach(QString s, counterParts) {
\r
287 cout << "cont part = " << qPrintable(s) << endl;
\r
289 double val = s.toDouble(&ok);
\r
291 productionCounter.append(val);
\r
293 else if (s.at(0) == '{') {
\r
296 QStringList gen = s.split(":");
\r
297 if (gen.size() != 3) {
\r
298 throw(Exception(INVALID_IFACE_PC,this));
\r
303 for(int i=0;i<3;i++) {
\r
304 double result = 0.0;
\r
306 result = evaluateExpression(gen.at(i));
\r
308 catch(Exception e) {
\r
311 if (i==0) start = result;
\r
312 else if (i==1) nb = result;
\r
313 else if (i==2) step = result;
\r
315 for(int j=0;j<nb;j++) {
\r
316 productionCounter.append(start+j*step);
\r
320 double result = 0.0;
\r
322 result = evaluateExpression(s);
\r
324 catch(Exception e) {
\r
327 productionCounter.append(result);
\r
330 foreach(int val, productionCounter) {
\r
331 cout << val << ",";
\r
336 QList<char>* FunctionalBlock::expandPattern(const QString& patternIn) throw(Exception) {
\r
337 static QString fctName = "FunctionalBlock::expandPattern()";
\r
338 #ifdef DEBUG_FCTNAME
\r
339 cout << "call to " << qPrintable(fctName) << endl;
\r
341 /* expanding a pattern is done in two steps :
\r
342 - 1 : finding all variables that correspond to an expression
\r
343 and copy them in the pattern
\r
344 - 2 : parsing the result
\r
346 Note that the result MUST contain only variables that have a
\r
347 integer/double value. Otherwise, expanding will fail.
\r
353 QString p = replaceExpressions(patternIn);
\r
358 QList<char>* patternOut = new QList<char>();
\r
360 patternOut->append(expandPatternRecur(p,&offset));
\r
362 catch(Exception e) {
\r
369 QString FunctionalBlock::replaceExpressions(const QString& patternIn) throw(Exception) {
\r
371 QString res = patternIn;
\r
373 QRegularExpression re("[$][a-zA-Z0-9_]+");
\r
377 QRegularExpressionMatchIterator matcher = re.globalMatch(res);
\r
378 while(matcher.hasNext()) {
\r
379 QRegularExpressionMatch m = matcher.next();
\r
380 QString param = m.captured(0);
\r
381 QString paramName = param;
\r
382 paramName.remove(0,1);
\r
383 BlockParameter* p = getParameterFromName(paramName);
\r
384 if ((p != NULL) && (p->getType() == BlockParameter::Expression)) {
\r
385 res.replace(param,p->getStringValue());
\r
387 cout << "found an expr: " << qPrintable(paramName) << ", patern => " << qPrintable(res) << endl;
\r
394 QList<char> FunctionalBlock::expandPatternRecur(const QString& patternIn, int *offset) throw(Exception) {
\r
396 QList<char> patternOut;
\r
398 while ((*offset < patternIn.size()) && (patternIn.at(*offset) != ')')) {
\r
400 QChar c = patternIn.at(*offset);
\r
404 patternOut.append(expandPatternRecur(patternIn,offset));
\r
406 catch(Exception e) {
\r
410 else if (c == '0') {
\r
411 patternOut.append(0);
\r
413 else if (c == '1') {
\r
414 patternOut.append(1);
\r
416 else if (c == 'X') {
\r
417 patternOut.append(-1);
\r
419 else if (c == '{') {
\r
421 QString expr = "";
\r
422 while ((*offset < patternIn.size()) && (patternIn.at(*offset) != '}')) {
\r
423 expr += patternIn.at(*offset);
\r
426 if (*offset == patternIn.size()) {
\r
427 throw(Exception(INVALID_IFACE_PATTERN,this));
\r
431 repeat = evaluateExpression(expr);
\r
433 catch(Exception e) {
\r
438 patternOut.removeLast();
\r
441 // repeat just the last value in currentGroup
\r
442 char last = patternOut.last();
\r
443 //cout << "repeat last char " << repeat << " times : " << (int)last << endl;
\r
444 for(int i=1;i<(int)repeat;i++) {
\r
445 patternOut.append(last);
\r
452 // must check if after ), there is a {
\r
453 if ((*offset < patternIn.size()-1) && (patternIn.at(*offset+1) == '{')) {
\r
455 QString expr = "";
\r
456 while ((*offset < patternIn.size()) && (patternIn.at(*offset) != '}')) {
\r
457 expr += patternIn.at(*offset);
\r
460 if (*offset == patternIn.size()) {
\r
461 throw(Exception(INVALID_IFACE_PATTERN,this));
\r
465 repeat = evaluateExpression(expr);
\r
467 catch(Exception e) {
\r
471 QList<char> voidList;
\r
476 cout << "repeat last group " << repeat << " times : ";
\r
477 foreach (char c, currentGroup) cout <<(int)c;
\r
480 QList<char> single = patternOut;
\r
481 for(int i=1;i<(int)repeat;i++) {
\r
482 patternOut.append(single);
\r
489 double FunctionalBlock::evaluateExpression(const QString& expression) throw(Exception) {
\r
490 static QString fctName = "FunctionalBlock::evaluateExpression()";
\r
491 #ifdef DEBUG_FCTNAME
\r
492 cout << "call to " << qPrintable(fctName) << endl;
\r
495 QHash<QString,double> vars;
\r
496 evaluator->setExpression(expression);
\r
497 QList<QString> varNames = evaluator->getVariableNames();
\r
498 foreach (QString name, varNames) {
\r
499 QString paramName = name;
\r
500 paramName.remove(0,1);
\r
501 BlockParameter* param = getParameterFromName(paramName);
\r
502 if (param == NULL) {
\r
503 throw(Exception(EVAL_PARAM_UNKNOWN,this));
\r
506 int val = param->getDoubleValue(&okVal);
\r
508 throw(Exception(EVAL_PARAM_NOVALUE,this));
\r
510 vars.insert(name,(double)val);
\r
513 evaluator->setVariablesValue(vars);
\r
514 double result = 0.0;
\r
516 result = evaluator->evaluate();
\r
519 cerr << "Error at index " << index << ": " << qPrintable(evaluator->getError()) << endl;
\r
520 throw(Exception(EVAL_INVALID_EXPR,this));
\r
525 void FunctionalBlock::computeAdmittanceDelays() throw(Exception) {
\r
526 static QString fctName = "FunctionalBlock::computeAdmittanceDelays()";
\r
527 #ifdef DEBUG_FCTNAME
\r
528 cout << "call to " << qPrintable(fctName) << endl;
\r
530 QList<int> inClock;
\r
533 clearAdmittanceDelays();
\r
535 // trying to synchronize the first one in AP
\r
536 QMapIterator<AbstractInterface*,QList<char>* > iterAP(admittance);
\r
537 QMapIterator<AbstractInterface*,QList<char>* > iterIP(inputPattern);
\r
539 while (iterAP.hasNext()) {
\r
542 QList<char>* ap = iterAP.value();
\r
543 QList<char>* ip = iterIP.value();
\r
545 while ((first < lengthIP) && (ip->at(first) == 0)) first++;
\r
546 while ((first < lengthAP) && (ap->at(first) == 0)) first--;
\r
547 delays.append(first);
\r
549 QList<int>* delays = new QList<int>();
\r
550 admittanceDelays.insert(iterAP.key(), delays);
\r
553 QMapIterator<AbstractInterface*,QList<int>* > iterDelays(admittanceDelays);
\r
555 // get the delay to apply
\r
557 for(int i=0;i<delays.size();i++) {
\r
558 if (delays[i] > maxDelay) maxDelay = delays[i];
\r
560 // adding the delays to IP
\r
563 while (iterIP.hasNext()) {
\r
566 QList<char>* ip = iterIP.value();
\r
567 QList<int>* d = iterDelays.value();
\r
568 d->append(maxDelay-delays[i]);
\r
569 cout << "prependind " << qPrintable(iterIP.key()->getName()) << " with " << (maxDelay-delays[i]) << " 0" << endl;
\r
570 for(int j=0;j<maxDelay-delays[i];j++) {
\r
573 for(int j=0;j<delays[i];j++) {
\r
578 lengthIP += maxDelay;
\r
580 cout << "IP length = " << lengthIP << ", AP length = " << lengthAP << endl;
\r
586 // if AP is a valid group, search for the next valid group in IP
\r
587 if (isValidDataGroup(admittance,apIndex)) {
\r
589 while ((ipIndex < lengthIP) && (! isValidDataGroup(inputPattern,ipIndex))) ipIndex++;
\r
590 if (ipIndex == lengthIP) {
\r
598 iterDelays.toFront();
\r
600 if (samePatterns(inputPattern,ipIndex,admittance,apIndex)) {
\r
601 while (iterAP.hasNext()) {
\r
604 QList<char>* ap = iterAP.value();
\r
605 if (ap->at(apIndex) == 1) {
\r
606 QList<int>* d = iterDelays.value();
\r
607 d->append(0); // the 1 is at its good place, so no delay
\r
612 cout << "diff between IP and AP at " << apIndex << endl;
\r
613 // search for the next 1 in IP for every input that has a 1 in AP
\r
615 while (iterAP.hasNext()) {
\r
619 QList<char>* ap = iterAP.value();
\r
620 QList<char>* ip = iterIP.value();
\r
621 QList<int>* d = iterDelays.value();
\r
622 // case 1: 1 in IP is too late
\r
623 if ((ap->at(apIndex) == 1) && (ip->at(ipIndex) == 0)) {
\r
625 while ( ((ipIndex+delay) < lengthIP) && (ip->at(ipIndex+delay) == 0) ) delay++;
\r
626 cout << "found a delay of " << (-delay) << " for iface " << qPrintable(iterAP.key()->getName()) << endl;
\r
627 // moving the 1 to its normal pos.
\r
628 ip->replace(ipIndex,1);
\r
629 ip->replace(ipIndex+delay,0);
\r
632 // case 2: 1 in IP is too soon
\r
633 else if ((ap->at(apIndex) == 0) && (ip->at(ipIndex) == 1)) {
\r
635 while ( ((apIndex+delay) < lengthAP) && (ap->at(apIndex+delay) == 0) ) delay++;
\r
636 cout << "found a delay of " << delay << " for iface " << qPrintable(iterAP.key()->getName()) << endl;
\r
637 // search for next 0 in IP to put the 1
\r
638 int k = ipIndex+delay;
\r
639 while ((k < lengthIP) && (ip->at(k) == 1)) k++;
\r
640 ip->replace(ipIndex,0);
\r
645 if (! samePatterns(inputPattern,inClock,admittance,apIndex)) {
\r
646 cout << "Abnormal case while searching for delays" << endl;
\r
652 if ((apIndex >= lengthAP) || (ipIndex >= lengthIP)) stop = true;
\r
654 iterDelays.toFront();
\r
655 while (iterDelays.hasNext()) {
\r
657 QList<int>* d = iterDelays.value();
\r
658 foreach(int v, *d) {
\r
666 void FunctionalBlock::createInputPattern() throw(Exception) {
\r
667 static QString fctName = "FunctionalBlock::createInputPattern())";
\r
668 #ifdef DEBUG_FCTNAME
\r
669 cout << "call to " << qPrintable(fctName) << endl;
\r
673 foreach(AbstractInterface* iface, getControlInputs()) {
\r
675 ConnectedInterface* connIface = AI_TO_CON(iface);
\r
676 // check if it is connected
\r
677 if (connIface->getConnectedFrom() == NULL) {
\r
678 throw(Exception(IFACE_NOT_CONNECTED,this));
\r
680 // get the precursor output pattern
\r
681 QList<char>* out = connIface->getConnectedFrom()->getOutputPattern();
\r
682 AbstractInputModifier* modifier = connIface->getInputModifier();
\r
683 // check if the input is modified
\r
684 if (modifier != NULL) {
\r
686 out = modifier->getModifiedInput(out);
\r
689 if (out->size() == 0) {
\r
690 clearInputPattern();
\r
691 throw(Exception(NO_IFACE_IP,this));
\r
693 if (lengthIP == -1) {
\r
694 lengthIP = out->size();
\r
697 if (out->size() < lengthIP) lengthIP = out->size();
\r
700 QList<char>* in = new QList<char>(*out);
\r
701 foreach(char c, *in) {
\r
705 inputPattern.insert(connIface,in);
\r
707 // search the last valid group in IP,
\r
708 while(! isValidDataGroup(inputPattern,lengthIP-1)) {
\r
709 //removeDataGroup(inputPattern,lengthIP-1);
\r
714 void FunctionalBlock::createAdmittance(int nbExec) throw(Exception) {
\r
715 static QString fctName = "FunctionalBlock::createAdmittance()";
\r
716 #ifdef DEBUG_FCTNAME
\r
717 cout << "call to " << qPrintable(fctName) << endl;
\r
719 // firstly, copy CP in AP
\r
720 QMapIterator<AbstractInterface*,QList<char>* > iterC(consumptionPattern);
\r
721 while (iterC.hasNext()) {
\r
723 QList<char>* pattern = new QList<char>(*(iterC.value()));
\r
724 admittance.insert(iterC.key(), pattern);
\r
726 lengthAP = lengthCP;
\r
728 cout << "trigger 1 at c.c. 0" << endl;
\r
729 for(int i=1;i<nbExec;i++) {
\r
730 // searching for the clock cycle for which a new exec starts
\r
732 while ((clock < lengthAP) && (nbGroup < delta)) {
\r
733 if (isValidDataGroup(admittance,clock)) nbGroup+=1;
\r
736 while ((clock < lengthAP) && (! isValidDataGroup(admittance,clock))) clock+=1;
\r
737 cout << "trigger " << (i+1) << " at c.c. " << clock << endl;
\r
739 // combine CP with AP at sc
\r
740 for(int j=0;j<lengthCP;j++) {
\r
741 // first case : column of CP must be placed beyond AP's end.
\r
742 if (sc == lengthAP) {
\r
743 cout << i << "," << j << " append in AP at " << sc << endl;
\r
744 appendToPattern(consumptionPattern,j,admittance,1);
\r
748 // second case : CP and AP can be combined directly (i.e. no X | 1 to do)
\r
749 else if (canCombinePatterns(consumptionPattern,j,admittance,sc)) {
\r
750 cout << i << "," << j << " combine at " << sc << endl;
\r
751 combinePatterns(consumptionPattern,j,admittance,sc);
\r
754 // third case : CP has an X column
\r
755 else if (isOnlyXDataGroup(consumptionPattern,j)) {
\r
756 cout << i << "," << j << " shift rigth AP to combine at " << sc << endl;
\r
757 shiftRightPattern(admittance,sc);
\r
759 if (! canCombinePatterns(consumptionPattern,j,admittance,sc)) {
\r
760 cerr << "Abnormal case when combining AP and CP" << endl;
\r
762 combinePatterns(consumptionPattern,j,admittance,sc);
\r
765 // fourth case : AP has an X column
\r
766 else if (isOnlyXDataGroup(admittance,sc)) {
\r
767 cout << i << "," << j << " jump c.c. for CP at " << sc << endl;
\r
772 throw(INVALID_DELTA_CP);
\r
776 // turn all X into 0
\r
777 QMapIterator<AbstractInterface*,QList<char>* > iterA(admittance);
\r
778 while (iterA.hasNext()) {
\r
780 QList<char>* pattern = iterA.value();
\r
781 for(int i=0;i<pattern->size();i++) {
\r
782 if (pattern->at(i) == -1) pattern->replace(i,0);
\r
783 cout << (int)(pattern->at(i));
\r
789 void FunctionalBlock::checkInputPatternCompatibility() throw(Exception) {
\r
790 static QString fctName = "FunctionalBlock::checkInputPatternCompatibility()";
\r
791 #ifdef DEBUG_FCTNAME
\r
792 cout << "call to " << qPrintable(fctName) << endl;
\r
795 // firstly, create input pattern
\r
797 createInputPattern();
\r
799 catch(Exception e) {
\r
802 int nbExec = createTriggers();
\r
803 cout << qPrintable(name) << " will exec. " << nbExec << " times." << endl;
\r
806 createAdmittance(nbExec);
\r
808 catch(Exception e) {
\r
809 cout << "cannot create admittance" << endl;
\r
813 int clock = 0; // index in IP
\r
814 int i = 0; // index in AP
\r
815 while ((clock < lengthIP) && (i < lengthAP)) {
\r
817 // if AP is a valid group, search for the next valid group in IP
\r
818 if (isValidDataGroup(admittance,i)) {
\r
819 while ((clock < lengthIP) && (! isValidDataGroup(inputPattern,clock))) clock++;
\r
820 if (clock == lengthIP) {
\r
821 cerr << "Abnormal case: end of IP has been reached without finding a valid group" << endl;
\r
822 throw(Exception(IP_END_NULLCOL,this));
\r
825 /* at that point 2 cases of compat : IP(clock) and AP(i) are equal valid group, or
\r
826 are both null columns
\r
828 if (! samePatterns(inputPattern,clock,admittance,i)) {
\r
829 cout << "AP(" << i << ") and IP(" << clock << ") are not equal" << endl;
\r
830 throw(Exception(IP_AP_NOTCOMPAT,this)); // IP and AP not compatible
\r
835 if (clock < lengthIP) {
\r
836 throw(Exception(AP_TOO_SHORT,this));
\r
837 cerr << "Abnormal case: AP is to short" << endl;
\r
841 void FunctionalBlock::computeOutputPattern(int nbExec) throw(Exception) {
\r
842 static QString fctName = "FunctionalBlock::computeOutputPattern()";
\r
843 #ifdef DEBUG_FCTNAME
\r
844 cout << "call to " << qPrintable(fctName) << endl;
\r
847 clearOutputPattern();
\r
849 /* case 1: the block is a generator for which output pattern
\r
850 must be computed for a nbExec following executions
\r
854 cout << "computing output pattern of " << qPrintable(name) << " for " << nbExec << " executions" << endl;
\r
855 foreach(AbstractInterface* iface, getControlOutputs()) {
\r
856 FunctionalInterface* connIface = AI_TO_FUN(iface);
\r
857 // create output pattern
\r
858 QList<char>* pp = productionPattern.value(connIface);
\r
859 QList<char>* pattern = new QList<char>(*pp);
\r
860 for(int i=1;i<nbExec;i++) pattern->append(*pp);
\r
861 // assign pattern to interface
\r
862 connIface->setOutputPattern(pattern);
\r
863 // store it in QMap
\r
864 outputPattern.insert(connIface,pattern);
\r
868 cout << "computing output pattern of " << qPrintable(name) << endl;
\r
870 // in case of inputPattern not created, do it
\r
871 if (lengthIP <= 0) {
\r
873 cout << "Strange case: input pattern is not created while it is time to compute output pattern !" << endl;
\r
874 // collect the input patterns for each input
\r
876 createInputPattern();
\r
878 catch(Exception e) {
\r
881 cout << "input pattern array initialized with min. len " << lengthIP << endl;
\r
884 // initialize the output pattern
\r
886 foreach(AbstractInterface* iface, getControlOutputs()) {
\r
887 FunctionalInterface* connIface = AI_TO_FUN(iface);
\r
888 lengthOP = lengthIP+productionPattern.value(connIface)->size();
\r
889 QList<char>* pattern = new QList<char>();
\r
890 for(int i=0;i<lengthOP;i++) pattern->append(0);
\r
891 connIface->setOutputPattern(pattern);
\r
892 outputPattern.insert(connIface,pattern);
\r
894 cout << "output pattern array initialized" << endl;
\r
898 // search for the beginning of the first execution.
\r
899 while ((clock < lengthIP) && (! isValidDataGroup(inputPattern,clock))) clock++;
\r
900 cout << "found 1st exec clock: " << clock << endl;
\r
902 while (clock < lengthIP) {
\r
903 // initialize counters for current execution.
\r
904 int p = 0; // index in production pattern
\r
905 int o = 0; // clock+o will give the clock cycle of each output group
\r
906 int cip = 0; // clock+cip give the clock cycle of an input group
\r
907 int ccp = 0; // ccp give a column in the consumptio pattern
\r
908 int nip = 0; // number of input data groups already consumed during the current execution, used while exploring IP
\r
909 int ncp = 0; // number of input data groups already consumed during the current execution, used while exploring CP
\r
910 bool cannotCompleteExec = false;
\r
911 for(int m=0;m<productionCounter.size();m++) {
\r
912 // search for the first production in PP
\r
913 while (!isValidDataGroup(productionPattern,p)) {
\r
917 int gap = 0; // count the number of extra null columns
\r
918 // search for PC(m) valid input group in IP
\r
919 while (nip < productionCounter.at(m)) {
\r
920 if (clock+cip < lengthIP) {
\r
921 if (isValidDataGroup(inputPattern,clock+cip)) nip += 1;
\r
926 cannotCompleteExec = true;
\r
931 if (cannotCompleteExec) break; // no need to go further since the next search of input data group will lead to go outside inputPattern
\r
933 // search for PC(m) valid input group in IP
\r
934 while (ncp < productionCounter.at(m)) {
\r
935 if (isValidDataGroup(consumptionPattern,ccp)) ncp += 1;
\r
939 o += gap; // to take into acocunt of extra null columns
\r
940 combinePatterns(productionPattern,p,outputPattern,clock+o);
\r
945 if (cannotCompleteExec) break; // no need to go further since the next search of input data group will lead to go outside inputPattern
\r
947 // current exec. taken into accunt
\r
950 // search for the next exec.
\r
953 while ((clock < lengthIP) && (nip < delta)) {
\r
954 if (isValidDataGroup(inputPattern,clock)) nip += 1;
\r
955 if (nip < delta) clock += 1;
\r
957 cout << "found exec " << nbExec << " at clock: " << clock << endl;
\r
959 // find the last valid output data group
\r
960 while(! isValidDataGroup(outputPattern,lengthOP-1)) {
\r
961 removeDataGroup(outputPattern,lengthOP-1);
\r
965 // clear input pattern
\r
966 clearInputPattern();
\r
972 void FunctionalBlock::computeOutputPattern(int nbExec) throw(Exception) {
\r
973 static QString fctName = "FunctionalBlock::computeOutputPattern()";
\r
974 #ifdef DEBUG_FCTNAME
\r
975 cout << "call to " << qPrintable(fctName) << endl;
\r
978 // case 1: the block is a generator for which output pattern
\r
979 // must be computed for a nbExec following executions
\r
982 cout << "computing output pattern of " << qPrintable(name) << " for " << nbExec << " executions" << endl;
\r
983 foreach(AbstractInterface* iface, getControlOutputs()) {
\r
984 FunctionalInterface* connIface = AI_TO_FUN(iface);
\r
985 // create output pattern
\r
986 QList<char>* pp = productionPattern.value(connIface);
\r
987 QList<char>* pattern = new QList<char>(*pp);
\r
988 for(int i=1;i<nbExec;i++) pattern->append(*pp);
\r
989 // assign pattern to interface
\r
990 connIface->setOutputPattern(pattern);
\r
991 // store it in QMap
\r
992 outputPattern.insert(connIface,pattern);
\r
996 cout << "computing output pattern of " << qPrintable(name) << endl;
\r
998 // in case of inputPattern not created, do it
\r
999 if (lengthIP <= 0) {
\r
1000 // collect the input patterns for each input
\r
1002 createInputPattern();
\r
1004 catch(Exception e) {
\r
1007 cout << "input pattern array initialized with min. len " << lengthIP << endl;
\r
1010 // initialize the output pattern
\r
1012 foreach(AbstractInterface* iface, getControlOutputs()) {
\r
1013 FunctionalInterface* connIface = AI_TO_FUN(iface);
\r
1014 lengthOP = lengthIP+productionPattern.value(connIface)->size();
\r
1015 QList<char>* pattern = new QList<char>();
\r
1016 for(int i=0;i<lengthOP;i++) pattern->append(0);
\r
1017 connIface->setOutputPattern(pattern);
\r
1018 outputPattern.insert(connIface,pattern);
\r
1020 cout << "output pattern array initialized" << endl;
\r
1024 // search for the beginning of the first execution.
\r
1025 while ((clock < lengthIP) && (! isValidDataGroup(inputPattern,clock))) clock++;
\r
1026 cout << "found 1st exec clock: " << clock << endl;
\r
1028 while (clock < lengthIP) {
\r
1029 // initialize counters for current execution.
\r
1030 int p = 0; // index in production pattern
\r
1031 int o = 0; // clock+o will give the clock cycle of each output group
\r
1032 int cip = 0; // clock+cip give the clock cycle of an input group
\r
1033 int ccp = 0; // ccp give a column in the consumptio pattern
\r
1034 int nip = 0; // number of input data groups already consumed during the current execution, used while exploring IP
\r
1035 int ncp = 0; // number of input data groups already consumed during the current execution, used while exploring CP
\r
1036 bool cannotCompleteExec = false;
\r
1037 for(int m=0;m<productionCounter.size();m++) {
\r
1038 // search for the first production in PP
\r
1039 while (!isValidDataGroup(productionPattern,p)) {
\r
1043 int gap = 0; // count the number of extra null columns
\r
1044 // search for PC(m) valid input group in IP
\r
1045 while (nip < productionCounter.at(m)) {
\r
1046 if (clock+cip < lengthIP) {
\r
1047 if (isValidDataGroup(inputPattern,clock+cip)) nip += 1;
\r
1052 cannotCompleteExec = true;
\r
1057 if (cannotCompleteExec) break; // no need to go further since the next search of input data group will lead to go outside inputPattern
\r
1059 // search for PC(m) valid input group in IP
\r
1060 while (ncp < productionCounter.at(m)) {
\r
1061 if (isValidDataGroup(consumptionPattern,ccp)) ncp += 1;
\r
1065 o += gap; // to take into acocunt of extra null columns
\r
1066 combinePatterns(productionPattern,p,outputPattern,clock+o);
\r
1071 if (cannotCompleteExec) break; // no need to go further since the next search of input data group will lead to go outside inputPattern
\r
1073 // current exec. taken into accunt
\r
1076 // search for the next exec.
\r
1079 while ((clock < lengthIP) && (nip < delta)) {
\r
1080 if (isValidDataGroup(inputPattern,clock)) nip += 1;
\r
1081 if (nip < delta) clock += 1;
\r
1083 cout << "found exec " << nbExec << " at clock: " << clock << endl;
\r
1085 // find the last valid output data group
\r
1086 while(! isValidDataGroup(outputPattern,lengthOP-1)) {
\r
1087 removeDataGroup(outputPattern,lengthOP-1);
\r
1091 // clear input pattern
\r
1092 clearInputPattern();
\r
1096 bool FunctionalBlock::samePatterns(const QMap<AbstractInterface*, QList<char>* >& patternSrc, int srcCol, const QMap<AbstractInterface*, QList<char>* >& patternDest, int destCol) {
\r
1098 if (patternSrc.size() != patternDest.size()) return false;
\r
1099 QMapIterator<AbstractInterface*, QList<char>* > iterSrc(patternSrc);
\r
1100 QMapIterator<AbstractInterface*, QList<char>* > iterDest(patternDest);
\r
1101 while (iterSrc.hasNext()) {
\r
1104 QList<char>* srcPat = iterSrc.value();
\r
1105 QList<char>* destPat = iterDest.value();
\r
1106 if (srcCol >= srcPat->size()) return false;
\r
1107 if (destCol >= destPat->size()) return false;
\r
1108 if (srcPat->at(srcCol) != destPat->at(destCol)) return false;
\r
1113 bool FunctionalBlock::samePatterns(const QMap<AbstractInterface*, QList<char>* >& patternSrc, const QList<int> &srcCols, const QMap<AbstractInterface*, QList<char>* >& patternDest, int destCol) {
\r
1114 if (patternSrc.size() != srcCols.size()) return false;
\r
1115 if (patternSrc.size() != patternDest.size()) return false;
\r
1117 QMapIterator<AbstractInterface*, QList<char>* > iterSrc(patternSrc);
\r
1118 QListIterator<int> iterSrcCol(srcCols);
\r
1119 QMapIterator<AbstractInterface*, QList<char>* > iterDest(patternDest);
\r
1120 while (iterSrc.hasNext()) {
\r
1122 int srcCol = iterSrcCol.next();
\r
1124 QList<char>* srcPat = iterSrc.value();
\r
1125 QList<char>* destPat = iterDest.value();
\r
1126 if (srcCol >= srcPat->size()) return false;
\r
1127 if (destCol >= destPat->size()) return false;
\r
1128 if (srcPat->at(srcCol) != destPat->at(destCol)) return false;
\r
1133 bool FunctionalBlock::canCombinePatterns(const QMap<AbstractInterface*, QList<char>* >& patternSrc, int srcCol, QMap<AbstractInterface*, QList<char>* > patternDest, int destCol) {
\r
1134 if (patternSrc.size() != patternDest.size()) return false;
\r
1135 QMapIterator<AbstractInterface*, QList<char>* > iterSrc(patternSrc);
\r
1136 QMapIterator<AbstractInterface*, QList<char>* > iterDest(patternDest);
\r
1137 while (iterSrc.hasNext()) {
\r
1140 QList<char>* srcPat = iterSrc.value();
\r
1141 QList<char>* destPat = iterDest.value();
\r
1142 if (srcCol >= srcPat->size()) return false;
\r
1143 if (destCol >= destPat->size()) return false;
\r
1144 if ((srcPat->at(srcCol) == -1) && (destPat->at(destCol) == 1)) return false;
\r
1145 if ((srcPat->at(srcCol) == 1) && (destPat->at(destCol) == -1)) return false;
\r
1150 void FunctionalBlock::combinePatterns(const QMap<AbstractInterface*, QList<char>* >& patternSrc, int srcCol, QMap<AbstractInterface*, QList<char>* > patternDest, int destCol) {
\r
1151 if (patternSrc.size() != patternDest.size()) return;
\r
1152 QMapIterator<AbstractInterface*, QList<char>* > iterSrc(patternSrc);
\r
1153 QMapIterator<AbstractInterface*, QList<char>* > iterDest(patternDest);
\r
1154 while (iterSrc.hasNext()) {
\r
1157 QList<char>* srcPat = iterSrc.value();
\r
1158 QList<char>* destPat = iterDest.value();
\r
1159 if (srcCol >= srcPat->size()) return;
\r
1160 if (destCol >= destPat->size()) return;
\r
1161 if ((srcPat->at(srcCol) == -1) && (destPat->at(destCol) == 1)) return;
\r
1162 if ((srcPat->at(srcCol) == 1) && (destPat->at(destCol) == -1)) return;
\r
1163 destPat->replace(destCol,destPat->at(destCol) | srcPat->at(srcCol));
\r
1167 void FunctionalBlock::appendToPattern(const QMap<AbstractInterface*, QList<char>* >& patternSrc, int srcCol, QMap<AbstractInterface*, QList<char>* > patternDest, int nbCols) {
\r
1168 if (patternSrc.size() != patternDest.size()) return;
\r
1169 QMapIterator<AbstractInterface*, QList<char>* > iterSrc(patternSrc);
\r
1170 QMapIterator<AbstractInterface*, QList<char>* > iterDest(patternDest);
\r
1171 while (iterSrc.hasNext()) {
\r
1174 QList<char>* srcPat = iterSrc.value();
\r
1175 QList<char>* destPat = iterDest.value();
\r
1177 while ((srcCol+i < srcPat->size()) && (i<nbCols)) {
\r
1178 destPat->append(srcPat->at(srcCol+i));
\r
1184 void FunctionalBlock::removeDataGroup(QMap<AbstractInterface *, QList<char> *> &pattern, int offset) {
\r
1185 QMapIterator<AbstractInterface*, QList<char>* > iterSrc(pattern);
\r
1186 while (iterSrc.hasNext()) {
\r
1188 QList<char>* srcPat = iterSrc.value();
\r
1189 if (offset < srcPat->size()) {
\r
1190 srcPat->removeAt(offset);
\r
1195 void FunctionalBlock::shiftRightPattern(const QMap<AbstractInterface *, QList<char> *> &pattern, int offset) {
\r
1196 QMapIterator<AbstractInterface*, QList<char>* > iterSrc(pattern);
\r
1197 while (iterSrc.hasNext()) {
\r
1199 QList<char>* srcPat = iterSrc.value();
\r
1200 if (offset < srcPat->size()) {
\r
1201 srcPat->insert(offset,0);
\r
1206 bool FunctionalBlock::isValidDataGroup(const QMap<AbstractInterface *, QList<char> *> &pattern, int offset) {
\r
1207 QMapIterator<AbstractInterface*, QList<char>* > iterSrc(pattern);
\r
1208 while (iterSrc.hasNext()) {
\r
1210 QList<char>* srcPat = iterSrc.value();
\r
1211 if (offset >= srcPat->size()) return false;
\r
1212 if (srcPat->at(offset) == 1) return true;
\r
1217 bool FunctionalBlock::isValidDataGroup(const QMap<AbstractInterface*, QList<char>* >& pattern, const QList<int> offsets) {
\r
1218 QMapIterator<AbstractInterface*, QList<char>* > iterSrc(pattern);
\r
1219 QListIterator<int> iterOffsets(offsets);
\r
1220 while (iterSrc.hasNext()) {
\r
1222 int offset = iterOffsets.next();
\r
1223 QList<char>* srcPat = iterSrc.value();
\r
1224 if (offset >= srcPat->size()) return false;
\r
1225 if (srcPat->at(offset) == 1) return true;
\r
1230 bool FunctionalBlock::isOnlyXDataGroup(const QMap<AbstractInterface *, QList<char> *> &pattern, int offset) {
\r
1231 QMapIterator<AbstractInterface*, QList<char>* > iterSrc(pattern);
\r
1232 while (iterSrc.hasNext()) {
\r
1234 QList<char>* srcPat = iterSrc.value();
\r
1235 if (offset >= srcPat->size()) return false;
\r
1236 if (srcPat->at(offset) != -1) return false;
\r
1241 void FunctionalBlock::clearConsumptionPattern() {
\r
1242 QMapIterator<AbstractInterface*, QList<char>* > iterP(consumptionPattern);
\r
1243 while (iterP.hasNext()) {
\r
1245 QList<char>* pattern = iterP.value();
\r
1246 if (pattern != NULL) delete pattern;
\r
1248 consumptionPattern.clear();
\r
1252 void FunctionalBlock::clearProductionPattern() {
\r
1253 QMapIterator<AbstractInterface*, QList<char>* > iterP(productionPattern);
\r
1254 while (iterP.hasNext()) {
\r
1256 QList<char>* pattern = iterP.value();
\r
1257 if (pattern != NULL) delete pattern;
\r
1259 productionPattern.clear();
\r
1263 void FunctionalBlock::clearInputPattern() {
\r
1265 QMapIterator<AbstractInterface*,QList<char>* > iterI(inputPattern);
\r
1266 while (iterI.hasNext()) {
\r
1268 QList<char>* pattern = iterI.value();
\r
1269 if (pattern != NULL) delete pattern;
\r
1271 inputPattern.clear();
\r
1275 void FunctionalBlock::clearOutputPattern() {
\r
1277 QMapIterator<AbstractInterface*,QList<char>* > iterO(outputPattern);
\r
1278 while (iterO.hasNext()) {
\r
1280 ConnectedInterface* connIface = AI_TO_CON(iterO.key());
\r
1281 connIface->resetOutputPattern();
\r
1282 QList<char>* pattern = iterO.value();
\r
1283 if (pattern != NULL) delete pattern;
\r
1285 outputPattern.clear();
\r
1289 void FunctionalBlock::clearAdmittanceDelays() {
\r
1290 QMapIterator<AbstractInterface*, QList<int>* > iterA(admittanceDelays);
\r
1291 while (iterA.hasNext()) {
\r
1293 QList<int>* d = iterA.value();
\r
1294 if (d != NULL) delete d;
\r
1296 admittanceDelays.clear();
\r
1299 int FunctionalBlock::createTriggers() {
\r
1301 /* NB: this method returns the number of executions that have been started
\r
1302 but not necessary completed.
\r
1304 if (delta <= 0) return 0;
\r
1306 // search for the first exec.
\r
1307 while ((offset < lengthIP) && (! isValidDataGroup(inputPattern,offset))) offset++;
\r
1308 if (offset == lengthIP) return 0;
\r
1309 triggers.append(offset);
\r
1311 for(int i = offset;i<lengthIP;i++) {
\r
1312 if (isValidDataGroup(inputPattern,i)) nbGroup++;
\r
1313 if (nbGroup == delta+1) {
\r
1314 triggers.append(i);
\r
1318 return triggers.size();
\r
1321 QList<QString> FunctionalBlock::getExternalResources() {
\r
1323 BlockImplementation* impl = reference->getImplementations().at(0); // for now only take first impl available
\r
1324 QList<QString> list = impl->getResources();
\r
1325 foreach(QString s, list) {
\r
1326 cout << qPrintable(s) << " ";
\r
1334 void FunctionalBlock::generateVHDL(const QString& path) throw(Exception){
\r
1336 BlockImplementation* impl = reference->getImplementations().at(0); // for now only take first impl available
\r
1338 QFile implFile(impl->getXmlFile());
\r
1340 // reading in into QDomDocument
\r
1341 QDomDocument document("implFile");
\r
1343 if (!implFile.open(QIODevice::ReadOnly)) {
\r
1344 throw(Exception(IMPLFILE_NOACCESS));
\r
1346 if (!document.setContent(&implFile)) {
\r
1348 throw(Exception(IMPLFILE_NOACCESS));
\r
1352 bool genController = false;
\r
1353 QString coreFile = "";
\r
1354 QString controllerFile = "";
\r
1356 if (reference->isWBConfigurable()) {
\r
1357 genController = true;
\r
1358 controllerFile = path;
\r
1359 controllerFile += "/";
\r
1360 controllerFile.append(name);
\r
1361 controllerFile.append("_ctrl.vhd");
\r
1364 controllerFile = "nofile.vhd";
\r
1368 coreFile.append(name);
\r
1369 coreFile.append(".vhd");
\r
1371 QFile vhdlCore(coreFile);
\r
1372 QFile vhdlController(controllerFile);
\r
1374 if (!vhdlCore.open(QIODevice::WriteOnly)) {
\r
1375 throw(Exception(VHDLFILE_NOACCESS));
\r
1378 if (genController) {
\r
1379 if (!vhdlController.open(QIODevice::WriteOnly)) {
\r
1380 throw(Exception(VHDLFILE_NOACCESS));
\r
1383 QTextStream outCore(&vhdlCore);
\r
1384 QTextStream outController;
\r
1385 if (genController) {
\r
1386 outController.setDevice(&vhdlController);
\r
1390 //Get the root element
\r
1391 QDomElement impl = document.documentElement();
\r
1392 QDomElement eltComments = impl.firstChildElement("comments");
\r
1393 generateComments(outCore,eltComments, coreFile);
\r
1394 QDomElement eltLibs = eltComments.nextSiblingElement("libraries");
\r
1395 generateLibraries(outCore, eltLibs);
\r
1396 generateEntity(outCore, genController);
\r
1397 QDomElement eltArch = eltLibs.nextSiblingElement("architecture");
\r
1398 generateArchitecture(outCore, eltArch );
\r
1399 if (genController) {
\r
1400 generateController(outController);
\r
1403 catch(Exception err) {
\r
1408 vhdlController.close();
\r
1412 void FunctionalBlock::generateComments(QTextStream& out, QDomElement &elt, QString coreFile) throw(Exception) {
\r
1414 for(int i = 0; i < 50; i++) {
\r
1417 out << "\n--" << endl;
\r
1418 QString fileName = coreFile;
\r
1419 out << "-- File : " << fileName << endl;
\r
1420 out << "--" << endl;
\r
1421 QDomElement eltAuthor = elt.firstChildElement("author");
\r
1422 QString firstName = eltAuthor.attribute("firstname","");
\r
1423 QString lastName = eltAuthor.attribute("lastname","");
\r
1424 QString mail = eltAuthor.attribute("mail","");
\r
1425 out << "-- Author(s) : "<<firstName+" "<<lastName<<" ("<<mail<<")" << endl;
\r
1426 out << "--" << endl;
\r
1427 QDomElement eltLog = eltAuthor.nextSiblingElement("log");
\r
1428 QString crea = eltLog.attribute("creation","");
\r
1429 out << "-- Creation Date : "<<crea<< endl;
\r
1430 out << "--" << endl;
\r
1431 QDomNodeList listModifs = eltLog.elementsByTagName("modification");
\r
1432 for(int j=0;j<listModifs.length();j++) {
\r
1433 QDomNode nodeModif = listModifs.at(j);
\r
1434 QDomElement eltModif = nodeModif.toElement();
\r
1436 out << "-- Description : " << endl;
\r
1437 out << reference->getDescription() << endl;
\r
1438 out << "--" << endl;
\r
1439 QDomElement eltNote = eltLog.nextSiblingElement("notes");
\r
1440 QDomElement note = eltNote.firstChildElement();
\r
1441 QString noteTxt = note.text();
\r
1442 out << "-- Notes :\n"<<noteTxt<<endl;
\r
1443 out << "--" << endl;
\r
1444 for(int i = 0; i < 50; i++) {
\r
1447 out << endl << endl;
\r
1450 void FunctionalBlock::generateLibraries(QTextStream& out, QDomElement &elt) throw(Exception) {
\r
1452 QDomNodeList listLib = elt.elementsByTagName("library");
\r
1453 for(int i = 0; i < listLib.length(); i++) {
\r
1454 QDomNode nodeLib = listLib.item(i);
\r
1455 QDomElement eltLib = nodeLib.toElement();
\r
1456 QString nameLib = eltLib.attribute("name","none");
\r
1457 out << "library " << nameLib << ";" << endl;
\r
1458 QDomNodeList listPack = eltLib.elementsByTagName("package");
\r
1459 for(int j = 0; j < listPack.length(); j++) {
\r
1460 QDomNode nodePack = listPack.item(j);
\r
1461 QDomElement eltPack = nodePack.toElement();
\r
1462 QString namePack = eltPack.attribute("name","none");
\r
1463 QString usePack = eltPack.attribute("use","none");
\r
1464 out << "use " << nameLib << "." << namePack << "." << usePack << ";" << endl;
\r
1471 void FunctionalBlock::generateEntityOrComponentBody(QTextStream& out, int indentLevel, bool hasController) throw(Exception) {
\r
1474 QString indent = "";
\r
1475 for(i=0;i<indentLevel;i++) {
\r
1479 //QList<BlockParameter*> listParams = reference->getParameters();
\r
1480 QList<AbstractInterface*> listInputs = getInputs();
\r
1481 QList<AbstractInterface*> listOutputs = getOutputs();
\r
1482 QList<AbstractInterface*> listBidirs = getBidirs();
\r
1484 // Generation of the generics
\r
1485 QList<BlockParameter*> listGenerics = getGenericParameters();
\r
1486 if ((!listGenerics.isEmpty()) || (hasController)) {
\r
1487 out << indent << " generic (" << endl;
\r
1488 if (hasController) {
\r
1489 out << indent << " wb_data_width : integer = 16;" << endl;
\r
1490 out << indent << " wb_addr_width : integer = 12";
\r
1491 if (!listGenerics.isEmpty()) out << indent << ";";
\r
1494 for(i=0;i<listGenerics.size()-1;i++) {
\r
1495 out << indent << " " << listGenerics.at(i)->toVHDL(BlockParameter::Entity, 0) << endl;
\r
1497 out << indent << " " << listGenerics.at(i)->toVHDL(BlockParameter::Entity,BlockParameter::NoComma) << endl;
\r
1499 out << indent << " );" << endl;
\r
1502 out << indent << " port (" << endl;
\r
1504 QString ports = "";
\r
1505 QTextStream outPorts(&ports);
\r
1507 // Generation of the clk & rst signals
\r
1508 outPorts << indent << " -- clk/rst" << endl;
\r
1509 foreach(AbstractInterface* iface, listInputs) {
\r
1510 if(iface->getPurpose() == AbstractInterface::Clock || iface->getPurpose() == AbstractInterface::Reset) {
\r
1511 outPorts << indent << " " << iface->getName() << " : in std_logic;" << endl;
\r
1514 foreach(AbstractInterface* iface, listOutputs) {
\r
1515 if(iface->getPurpose() == AbstractInterface::Clock || iface->getPurpose() == AbstractInterface::Reset) {
\r
1516 outPorts << indent << " " << iface->getName() << " : out std_logic;" << endl;
\r
1520 if (hasController) {
\r
1521 // Generation of the wishbone signals
\r
1522 outPorts << indent << " -- registers r/w via wishbone" << endl;
\r
1523 QList<BlockParameter*> listWB = reference->getWishboneParameters();
\r
1524 for(i=0;i<listWB.size()-1;i++) {
\r
1525 outPorts << indent << " " << listWB.at(i)->toVHDL(BlockParameter::Entity, 0) << endl;
\r
1527 outPorts << indent << " " << listWB.at(i)->toVHDL(BlockParameter::Entity,BlockParameter::NoComma) << endl;
\r
1530 // Generation of the data/control signals
\r
1532 QList<AbstractInterface*> listIface = getInterfaces(AbstractInterface::Input, AbstractInterface::Data);
\r
1533 if (listIface.size()>0) {
\r
1534 outPorts << indent << " -- input data ports" << endl;
\r
1535 foreach(AbstractInterface* iface, listIface) {
\r
1536 outPorts << indent << " " << iface->toVHDL(AbstractInterface::Entity, 0) << endl;
\r
1539 listIface = getInterfaces(AbstractInterface::Input, AbstractInterface::Control);
\r
1540 if (listIface.size()>0) {
\r
1541 outPorts << indent << " -- input control ports" << endl;
\r
1542 foreach(AbstractInterface* iface, listIface) {
\r
1543 outPorts << indent << " " << iface->toVHDL(AbstractInterface::Entity, 0) << endl;
\r
1546 listIface = getInterfaces(AbstractInterface::Output, AbstractInterface::Data);
\r
1547 if (listIface.size()>0) {
\r
1548 outPorts << indent << " -- output data ports" << endl;
\r
1549 foreach(AbstractInterface* iface, listIface) {
\r
1550 outPorts << indent << " " << iface->toVHDL(AbstractInterface::Entity, 0) << endl;
\r
1553 listIface = getInterfaces(AbstractInterface::Output, AbstractInterface::Control);
\r
1554 if (listIface.size()>0) {
\r
1555 outPorts << indent << " -- output control ports" << endl;
\r
1556 foreach(AbstractInterface* iface, listIface) {
\r
1557 outPorts << indent << " " << iface->toVHDL(AbstractInterface::Entity, 0) << endl;
\r
1560 listIface = getInterfaces(AbstractInterface::InOut, AbstractInterface::Data);
\r
1561 if (listIface.size()>0) {
\r
1562 outPorts << indent << " -- bidirs data ports" << endl;
\r
1563 foreach(AbstractInterface* iface, listIface) {
\r
1564 outPorts << indent << " " << iface->toVHDL(AbstractInterface::Entity, 0) << endl;
\r
1571 out << indent << " );" << endl << endl;
\r
1575 void FunctionalBlock::generateArchitecture(QTextStream& out, QDomElement &elt ) throw(Exception) {
\r
1576 QRegularExpression rxPort("@\\{([a-zA-Z0-9_]+)\\}");
\r
1578 QString code = elt.text();
\r
1579 //cout << qPrintable(code) << endl;
\r
1580 out << "architecture rtl of " << name << " is" << endl;
\r
1582 QStringList listLine = code.split("\n");
\r
1583 for(int i =0; i < listLine.size(); i++) {
\r
1584 QString line = listLine.at(i).simplified();
\r
1587 if(listLine.at(i).contains(QRegularExpression("@foreach{"))) {
\r
1588 while(listLine.at(i).compare("@endforeach") != -1) {
\r
1589 expr = expr + listLine.at(i) + '\n';
\r
1592 expr = expr + listLine.at(i);
\r
1593 out << evalComplex(expr, 1) << '\n';
\r
1595 if(listLine.at(i).contains(QRegularExpression("@caseeach{"))) {
\r
1596 while(listLine.at(i).compare("@endcaseeach") != -1) {
\r
1597 expr = expr + listLine.at(i) + '\n';
\r
1600 expr = expr + listLine.at(i);
\r
1601 out << evalComplex(expr, 2) << '\n';
\r
1604 if(line.contains("@{")) {
\r
1605 QMap<QString,QString> modifs;
\r
1606 //cout << qPrintable(line) << endl;
\r
1607 QRegularExpressionMatchIterator matchPort = rxPort.globalMatch(line);
\r
1608 while(matchPort.hasNext()) {
\r
1609 QRegularExpressionMatch m = matchPort.next();
\r
1610 QString refName = m.captured(1);
\r
1611 AbstractInterface* refIface = reference->getIfaceFromName(refName);
\r
1612 QString funName = getIfaceUserName(refIface);
\r
1613 if (!funName.isEmpty()) {
\r
1614 modifs.insert(m.captured(0),funName);
\r
1615 //cout << "replace " << qPrintable(refIface->getName()) << " by " << qPrintable(funIface->getName()) << endl;
\r
1618 QMapIterator<QString,QString> iterM(modifs);
\r
1619 while(iterM.hasNext()) {
\r
1621 QString oldName = iterM.key();
\r
1622 QString newName = iterM.value();
\r
1623 line.replace(oldName,newName);
\r
1626 out << line << endl;
\r
1629 out << "end rtl;" << endl;
\r
1632 void FunctionalBlock::generateController(QTextStream &out) throw(Exception) {
\r
1636 QString FunctionalBlock::getIfaceUserName(AbstractInterface* refIface) {
\r
1638 if (! refIface->isReferenceInterface()) return "";
\r
1640 AbstractInterface* funcIface = NULL;
\r
1642 if (refIface->getDirection() == AbstractInterface::Input) {
\r
1643 foreach(AbstractInterface* iface, getInputs()) {
\r
1644 FunctionalInterface* fi = AI_TO_FUN(iface);
\r
1645 if (fi->getReference() == refIface) {
\r
1646 funcIface = iface;
\r
1651 else if (refIface->getDirection() == AbstractInterface::Output) {
\r
1652 foreach(AbstractInterface* iface, getOutputs()) {
\r
1653 FunctionalInterface* fi = AI_TO_FUN(iface);
\r
1654 if (fi->getReference() == refIface) {
\r
1655 funcIface = iface;
\r
1660 else if (refIface->getDirection() == AbstractInterface::InOut) {
\r
1661 foreach(AbstractInterface* iface, getBidirs()) {
\r
1662 FunctionalInterface* fi = AI_TO_FUN(iface);
\r
1663 if (fi->getReference() == refIface) {
\r
1664 funcIface = iface;
\r
1669 if (funcIface == NULL) return "";
\r
1671 return funcIface->getName();
\r