X-Git-Url: https://bilbo.iut-bm.univ-fcomte.fr/and/gitweb/blast.git/blobdiff_plain/56f7c4239666506c59af42885f0bf0141d21a614..c85843afb9bd492b46d6fe87a8287157097483f5:/FunctionalBlock.cpp diff --git a/FunctionalBlock.cpp b/FunctionalBlock.cpp index 7be000a..8ecd6a3 100644 --- a/FunctionalBlock.cpp +++ b/FunctionalBlock.cpp @@ -29,6 +29,7 @@ FunctionalBlock::FunctionalBlock(GroupBlock *_parent, ReferenceBlock *_reference lengthPP = -1; delta = -1; evaluator = NULL; + } FunctionalBlock::~FunctionalBlock() { @@ -77,6 +78,8 @@ void FunctionalBlock::populate() { addParameter(p); } + ConnectedInterface* toClk = NULL; + ConnectedInterface* toRst = NULL; // create interfaces from reference block QList lstRef = reference->getInterfaces(); // store relation between functional and reference @@ -90,8 +93,19 @@ void FunctionalBlock::populate() { exit(1); } hashIface.insert(lstRef.at(i),inter); - addInterface(inter); + /* WARNING FOR THE FUTURE : + in case of there are several clock interfaces ofr that block + it would be a godd idea to make the user choose which one + must be connected to defautl clk. + Presently, the first encountered is chosen + */ + if ((toClk == NULL) && (inter->getPurpose() == AbstractInterface::Clock)) { + toClk = AI_TO_CON(inter); + } + if ((toRst == NULL) && (inter->getPurpose() == AbstractInterface::Reset)) { + toRst = AI_TO_CON(inter); + } } AbstractInterface* funCtlIface = NULL; @@ -108,8 +122,19 @@ void FunctionalBlock::populate() { } } } -} + // connect clk and rst to group clk/rst or to clkrstgen + if ((name != "clkrstgen") && (parent != NULL)) { + try { + connectClkReset(); + } + catch(Exception e) { + AbstractBlock* source = (AbstractBlock *)(e.getSource()); + cerr << qPrintable(source->getName()) << ":" << qPrintable(e.getMessage()) << endl; + throw(e); + } + } +} QString FunctionalBlock::getReferenceXmlFile() { return ((ReferenceBlock *)reference)->getXmlFile(); @@ -184,6 +209,9 @@ void FunctionalBlock::createConsumptionPattern() throw(Exception) { cout << "call to " << qPrintable(fctName) << endl; #endif + // first clear if already exists + clearConsumptionPattern(); + lengthCP = -1; QHash consPattern = implementation->getConsumptionPattern(); @@ -191,7 +219,7 @@ void FunctionalBlock::createConsumptionPattern() throw(Exception) { FunctionalInterface* connIface = AI_TO_FUN(iface); QString refName = connIface->getReference()->getName(); if (! consPattern.contains(refName)) { - throw(Exception(NO_IFACE_CP)); + throw(Exception(NO_IFACE_CP,this)); cerr << "no consumption pattern for reference interface " << qPrintable(refName) << endl; } QList* pattern = NULL; @@ -207,7 +235,7 @@ void FunctionalBlock::createConsumptionPattern() throw(Exception) { } else { if (pattern->size() != lengthCP) { - throw(Exception(INVALID_IFACE_CP_LENGTH)); + throw(Exception(INVALID_IFACE_CP_LENGTH,this)); } } } @@ -218,6 +246,9 @@ void FunctionalBlock::createProductionPattern() throw(Exception){ #ifdef DEBUG_FCTNAME cout << "call to " << qPrintable(fctName) << endl; #endif + + // first clear if already exists + clearProductionPattern(); lengthPP = -1; QHash prodPattern = implementation->getProductionPattern(); @@ -226,7 +257,7 @@ void FunctionalBlock::createProductionPattern() throw(Exception){ FunctionalInterface* connIface = AI_TO_FUN(iface); QString refName = connIface->getReference()->getName(); if (! prodPattern.contains(refName)) { - throw(Exception(NO_IFACE_PP)); + throw(Exception(NO_IFACE_PP,this)); } QList* pattern = NULL; try { @@ -241,7 +272,7 @@ void FunctionalBlock::createProductionPattern() throw(Exception){ } else { if (pattern->size() != lengthPP) { - throw(Exception(INVALID_IFACE_PP_LENGTH)); + throw(Exception(INVALID_IFACE_PP_LENGTH,this)); } } } @@ -252,6 +283,10 @@ void FunctionalBlock::createProductionCounter() throw(Exception) { #ifdef DEBUG_FCTNAME cout << "call to " << qPrintable(fctName) << endl; #endif + + // first clear if already exists + productionCounter.clear(); + QStringList counterParts = implementation->getProductionCounter().split(","); foreach(QString s, counterParts) { @@ -266,7 +301,7 @@ void FunctionalBlock::createProductionCounter() throw(Exception) { s.chop(1); QStringList gen = s.split(":"); if (gen.size() != 3) { - throw(Exception(INVALID_IFACE_PC)); + throw(Exception(INVALID_IFACE_PC,this)); } int start = 0; int nb = 0; @@ -309,9 +344,21 @@ QList* FunctionalBlock::expandPattern(const QString& patternIn) throw(Exce #ifdef DEBUG_FCTNAME cout << "call to " << qPrintable(fctName) << endl; #endif - - QList lst; - QString p = patternIn; + /* expanding a pattern is done in two steps : + - 1 : finding all variables that correspond to an expression + and copy them in the pattern + - 2 : parsing the result + + Note that the result MUST contain only variables that have a + integer/double value. Otherwise, expanding will fail. + + */ + + // first step. + + QString p = replaceExpressions(patternIn); + + QList lst; p.append(')'); int offset = 0; QList* patternOut = new QList(); @@ -325,6 +372,31 @@ QList* FunctionalBlock::expandPattern(const QString& patternIn) throw(Exce return patternOut; } +QString FunctionalBlock::replaceExpressions(const QString& patternIn) throw(Exception) { + + QString res = patternIn; + bool stop = false; + QRegularExpression re("[$][a-zA-Z0-9_]+"); + + while (!stop) { + stop = true; + QRegularExpressionMatchIterator matcher = re.globalMatch(res); + while(matcher.hasNext()) { + QRegularExpressionMatch m = matcher.next(); + QString param = m.captured(0); + QString paramName = param; + paramName.remove(0,1); + BlockParameter* p = getParameterFromName(paramName); + if ((p != NULL) && (p->getType() == BlockParameter::Expression)) { + res.replace(param,p->getStringValue()); + stop = false; + cout << "found an expr: " << qPrintable(paramName) << ", patern => " << qPrintable(res) << endl; + } + } + } + return res; +} + QList FunctionalBlock::expandPatternRecur(const QString& patternIn, int *offset) throw(Exception) { QList patternOut; @@ -358,7 +430,7 @@ QList FunctionalBlock::expandPatternRecur(const QString& patternIn, int *o *offset += 1; } if (*offset == patternIn.size()) { - throw(Exception(INVALID_IFACE_PATTERN)); + throw(Exception(INVALID_IFACE_PATTERN,this)); } double repeat = 0; try { @@ -387,7 +459,7 @@ QList FunctionalBlock::expandPatternRecur(const QString& patternIn, int *o *offset += 1; } if (*offset == patternIn.size()) { - throw(Exception(INVALID_IFACE_PATTERN)); + throw(Exception(INVALID_IFACE_PATTERN,this)); } double repeat = 0; try { @@ -421,14 +493,14 @@ double FunctionalBlock::evaluateExpression(const QString& expression) throw(Exce foreach (QString name, varNames) { QString paramName = name; paramName.remove(0,1); - BlockParameter* param = reference->getParameterFromName(paramName); + BlockParameter* param = getParameterFromName(paramName); if (param == NULL) { - throw(Exception(EVAL_PARAM_UNKNOWN)); + throw(Exception(EVAL_PARAM_UNKNOWN,this)); } bool okVal; - int val = param->getDoubleValue(&okVal); + int val = param->getDoubleValue(&okVal); if (!okVal) { - throw(Exception(EVAL_PARAM_NOVALUE)); + throw(Exception(EVAL_PARAM_NOVALUE,this)); } vars.insert(name,(double)val); } @@ -440,11 +512,152 @@ double FunctionalBlock::evaluateExpression(const QString& expression) throw(Exce } catch(int index) { cerr << "Error at index " << index << ": " << qPrintable(evaluator->getError()) << endl; - throw(Exception(EVAL_INVALID_EXPR)); + throw(Exception(EVAL_INVALID_EXPR,this)); } return result; } +void FunctionalBlock::computeAdmittanceDelays() throw(Exception) { + static QString fctName = "FunctionalBlock::computeAdmittanceDelays()"; +#ifdef DEBUG_FCTNAME + cout << "call to " << qPrintable(fctName) << endl; +#endif + QList inClock; + QList delays; + + clearAdmittanceDelays(); + + // trying to synchronize the first one in AP + QMapIterator* > iterAP(admittance); + QMapIterator* > iterIP(inputPattern); + + while (iterAP.hasNext()) { + iterAP.next(); + iterIP.next(); + QList* ap = iterAP.value(); + QList* ip = iterIP.value(); + int first = 0; + while ((first < lengthIP) && (ip->at(first) == 0)) first++; + while ((first < lengthAP) && (ap->at(first) == 0)) first--; + delays.append(first); + inClock.append(0); + QList* delays = new QList(); + admittanceDelays.insert(iterAP.key(), delays); + } + + QMapIterator* > iterDelays(admittanceDelays); + + // get the delay to apply + int maxDelay = 0; + for(int i=0;i maxDelay) maxDelay = delays[i]; + } + // adding the delays to IP + iterIP.toFront(); + int i = 0; + while (iterIP.hasNext()) { + iterIP.next(); + iterDelays.next(); + QList* ip = iterIP.value(); + QList* d = iterDelays.value(); + d->append(maxDelay-delays[i]); + cout << "prependind " << qPrintable(iterIP.key()->getName()) << " with " << (maxDelay-delays[i]) << " 0" << endl; + for(int j=0;jprepend(0); + } + for(int j=0;jappend(0); + } + i++; + } + lengthIP += maxDelay; + + cout << "IP length = " << lengthIP << ", AP length = " << lengthAP << endl; + bool stop = false; + int apIndex = 0; + int ipIndex = 0; + while (!stop) { + + // if AP is a valid group, search for the next valid group in IP + if (isValidDataGroup(admittance,apIndex)) { + + while ((ipIndex < lengthIP) && (! isValidDataGroup(inputPattern,ipIndex))) ipIndex++; + if (ipIndex == lengthIP) { + stop = true; + continue; + } + } + + iterAP.toFront(); + iterIP.toFront(); + iterDelays.toFront(); + + if (samePatterns(inputPattern,ipIndex,admittance,apIndex)) { + while (iterAP.hasNext()) { + iterAP.next(); + iterDelays.next(); + QList* ap = iterAP.value(); + if (ap->at(apIndex) == 1) { + QList* d = iterDelays.value(); + d->append(0); // the 1 is at its good place, so no delay + } + } + } + else { + cout << "diff between IP and AP at " << apIndex << endl; + // search for the next 1 in IP for every input that has a 1 in AP + + while (iterAP.hasNext()) { + iterAP.next(); + iterIP.next(); + iterDelays.next(); + QList* ap = iterAP.value(); + QList* ip = iterIP.value(); + QList* d = iterDelays.value(); + // case 1: 1 in IP is too late + if ((ap->at(apIndex) == 1) && (ip->at(ipIndex) == 0)) { + int delay = 1; + while ( ((ipIndex+delay) < lengthIP) && (ip->at(ipIndex+delay) == 0) ) delay++; + cout << "found a delay of " << (-delay) << " for iface " << qPrintable(iterAP.key()->getName()) << endl; + // moving the 1 to its normal pos. + ip->replace(ipIndex,1); + ip->replace(ipIndex+delay,0); + d->append(-delay); + } + // case 2: 1 in IP is too soon + else if ((ap->at(apIndex) == 0) && (ip->at(ipIndex) == 1)) { + int delay = 1; + while ( ((apIndex+delay) < lengthAP) && (ap->at(apIndex+delay) == 0) ) delay++; + cout << "found a delay of " << delay << " for iface " << qPrintable(iterAP.key()->getName()) << endl; + // search for next 0 in IP to put the 1 + int k = ipIndex+delay; + while ((k < lengthIP) && (ip->at(k) == 1)) k++; + ip->replace(ipIndex,0); + ip->replace(k,1); + d->append(delay); + } + } + if (! samePatterns(inputPattern,inClock,admittance,apIndex)) { + cout << "Abnormal case while searching for delays" << endl; + } + } + + apIndex++; + ipIndex++; + if ((apIndex >= lengthAP) || (ipIndex >= lengthIP)) stop = true; + } + iterDelays.toFront(); + while (iterDelays.hasNext()) { + iterDelays.next(); + QList* d = iterDelays.value(); + foreach(int v, *d) { + cout << v << " "; + } + cout << endl; + } + +} + void FunctionalBlock::createInputPattern() throw(Exception) { static QString fctName = "FunctionalBlock::createInputPattern())"; #ifdef DEBUG_FCTNAME @@ -452,12 +665,25 @@ void FunctionalBlock::createInputPattern() throw(Exception) { #endif lengthIP = -1; - foreach(AbstractInterface* iface, getControlInputs()) { + foreach(AbstractInterface* iface, getControlInputs()) { + ConnectedInterface* connIface = AI_TO_CON(iface); + // check if it is connected + if (connIface->getConnectedFrom() == NULL) { + throw(Exception(IFACE_NOT_CONNECTED,this)); + } + // get the precursor output pattern QList* out = connIface->getConnectedFrom()->getOutputPattern(); + AbstractInputModifier* modifier = connIface->getInputModifier(); + // check if the input is modified + if (modifier != NULL) { + + out = modifier->getModifiedInput(out); + } + if (out->size() == 0) { clearInputPattern(); - throw(Exception(NO_IFACE_IP)); + throw(Exception(NO_IFACE_IP,this)); } if (lengthIP == -1) { lengthIP = out->size(); @@ -588,7 +814,7 @@ void FunctionalBlock::checkInputPatternCompatibility() throw(Exception) { while ((clock < lengthIP) && (! isValidDataGroup(inputPattern,clock))) clock++; if (clock == lengthIP) { cerr << "Abnormal case: end of IP has been reached without finding a valid group" << endl; - throw(Exception(IP_END_NULLCOL)); + throw(Exception(IP_END_NULLCOL,this)); } } /* at that point 2 cases of compat : IP(clock) and AP(i) are equal valid group, or @@ -596,13 +822,13 @@ void FunctionalBlock::checkInputPatternCompatibility() throw(Exception) { */ if (! samePatterns(inputPattern,clock,admittance,i)) { cout << "AP(" << i << ") and IP(" << clock << ") are not equal" << endl; - throw(Exception(IP_AP_NOTCOMPAT)); // IP and AP not compatible + throw(Exception(IP_AP_NOTCOMPAT,this)); // IP and AP not compatible } clock++; i++; } if (clock < lengthIP) { - throw(Exception(AP_TOO_SHORT)); + throw(Exception(AP_TOO_SHORT,this)); cerr << "Abnormal case: AP is to short" << endl; } } @@ -612,12 +838,13 @@ void FunctionalBlock::computeOutputPattern(int nbExec) throw(Exception) { #ifdef DEBUG_FCTNAME cout << "call to " << qPrintable(fctName) << endl; #endif - + + clearOutputPattern(); + /* case 1: the block is a generator for which output pattern must be computed for a nbExec following executions */ - - + if (nbExec > 0) { cout << "computing output pattern of " << qPrintable(name) << " for " << nbExec << " executions" << endl; foreach(AbstractInterface* iface, getControlOutputs()) { @@ -637,6 +864,8 @@ void FunctionalBlock::computeOutputPattern(int nbExec) throw(Exception) { // in case of inputPattern not created, do it if (lengthIP <= 0) { + + cout << "Strange case: input pattern is not created while it is time to compute output pattern !" << endl; // collect the input patterns for each input try { createInputPattern(); @@ -876,6 +1105,26 @@ bool FunctionalBlock::samePatterns(const QMap* > return true; } +bool FunctionalBlock::samePatterns(const QMap* >& patternSrc, const QList &srcCols, const QMap* >& patternDest, int destCol) { + if (patternSrc.size() != srcCols.size()) return false; + if (patternSrc.size() != patternDest.size()) return false; + + QMapIterator* > iterSrc(patternSrc); + QListIterator iterSrcCol(srcCols); + QMapIterator* > iterDest(patternDest); + while (iterSrc.hasNext()) { + iterSrc.next(); + int srcCol = iterSrcCol.next(); + iterDest.next(); + QList* srcPat = iterSrc.value(); + QList* destPat = iterDest.value(); + if (srcCol >= srcPat->size()) return false; + if (destCol >= destPat->size()) return false; + if (srcPat->at(srcCol) != destPat->at(destCol)) return false; + } + return true; +} + bool FunctionalBlock::canCombinePatterns(const QMap* >& patternSrc, int srcCol, QMap* > patternDest, int destCol) { if (patternSrc.size() != patternDest.size()) return false; QMapIterator* > iterSrc(patternSrc); @@ -960,6 +1209,19 @@ bool FunctionalBlock::isValidDataGroup(const QMap* >& pattern, const QList offsets) { + QMapIterator* > iterSrc(pattern); + QListIterator iterOffsets(offsets); + while (iterSrc.hasNext()) { + iterSrc.next(); + int offset = iterOffsets.next(); + QList* srcPat = iterSrc.value(); + if (offset >= srcPat->size()) return false; + if (srcPat->at(offset) == 1) return true; + } + return false; +} + bool FunctionalBlock::isOnlyXDataGroup(const QMap *> &pattern, int offset) { QMapIterator* > iterSrc(pattern); while (iterSrc.hasNext()) { @@ -1005,6 +1267,30 @@ void FunctionalBlock::clearInputPattern() { lengthIP = -1; } +void FunctionalBlock::clearOutputPattern() { + + QMapIterator* > iterO(outputPattern); + while (iterO.hasNext()) { + iterO.next(); + ConnectedInterface* connIface = AI_TO_CON(iterO.key()); + connIface->resetOutputPattern(); + QList* pattern = iterO.value(); + if (pattern != NULL) delete pattern; + } + outputPattern.clear(); + lengthOP = -1; +} + +void FunctionalBlock::clearAdmittanceDelays() { + QMapIterator* > iterA(admittanceDelays); + while (iterA.hasNext()) { + iterA.next(); + QList* d = iterA.value(); + if (d != NULL) delete d; + } + admittanceDelays.clear(); +} + int FunctionalBlock::createTriggers() { triggers.clear(); /* NB: this method returns the number of executions that have been started