X-Git-Url: https://bilbo.iut-bm.univ-fcomte.fr/and/gitweb/blast.git/blobdiff_plain/5d4e709cb8d460b2efc083e6e7999f1c3a0eb602..3fb762e7042d9b4a1cf78556ad9ed7f117cc53ba:/FunctionalBlock.cpp?ds=sidebyside diff --git a/FunctionalBlock.cpp b/FunctionalBlock.cpp index 5731794..0fb38c3 100644 --- a/FunctionalBlock.cpp +++ b/FunctionalBlock.cpp @@ -5,20 +5,16 @@ #include "FunctionalInterface.h" #include "ReferenceInterface.h" #include "BlockParameter.h" +#include "ArithmeticEvaluator.h" -FunctionalBlock::FunctionalBlock(GroupBlock *_parent, ReferenceBlock *_reference) throw(Exception) : AbstractBlock() { +FunctionalBlock::FunctionalBlock(GroupBlock *_parent, ReferenceBlock *_reference, bool createIfaces) throw(Exception) : AbstractBlock() { //if (! _reference->isReferenceBlock()) throw(Exception(BLOCK_INVALID_TYPE)); //if (! _group->isGroupBlock()) throw(Exception(BLOCK_INVALID_TYPE)); reference = _reference; parent = _parent; name = reference->getName(); - consumptionPattern = NULL; - lengthCP = 0; - nbConsumingPorts = 0; - productionPattern = NULL; - lengthPP = 0; - nbProducingPorts = 0; + if (reference->getImplementations().isEmpty()) { implementation = NULL; cout << "block has no implementation" << endl; @@ -26,8 +22,23 @@ FunctionalBlock::FunctionalBlock(GroupBlock *_parent, ReferenceBlock *_reference else { implementation = reference->getImplementations().at(0); } + lengthAP = -1; + lengthCP = -1; + lengthIP = -1; + lengthOP = -1; + lengthPP = -1; + delta = -1; + evaluator = NULL; + + if (createIfaces) { + populate(); + } + } +FunctionalBlock::~FunctionalBlock() { + if (evaluator != NULL) delete evaluator; +} void FunctionalBlock::parametersValidation(QList* checkedBlocks, QList *blocksToConfigure) { /* @@ -54,7 +65,7 @@ bool FunctionalBlock::isFunctionalBlock() { return true; } -bool FunctionalBlock::isSourceBlock() { +bool FunctionalBlock::isStimuliBlock() { if (parent == NULL) return true; return false; } @@ -71,6 +82,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 @@ -84,8 +97,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 good 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; @@ -104,7 +128,6 @@ void FunctionalBlock::populate() { } } - QString FunctionalBlock::getReferenceXmlFile() { return ((ReferenceBlock *)reference)->getXmlFile(); } @@ -113,135 +136,884 @@ QString FunctionalBlock::getReferenceHashMd5() { return ((ReferenceBlock *)reference)->getHashMd5(); } -bool FunctionalBlock::createPatterns() { - evaluator = new ArithmeticEvaluator(); - bool ok = true; - ok = ok & createDelta(); - if (ok) ok = ok & createConsumptionPattern(); - if (ok) ok = ok & createProductionCounter(); - if (ok) ok = ok & createProductionPattern(); - delete evaluator; - return ok; +void FunctionalBlock::createPatterns() throw(Exception) { + static QString fctName = "FunctionalBlock::createPatterns()"; +#ifdef DEBUG_FCTNAME + cout << "call to " << qPrintable(fctName) << endl; +#endif + + if (implementation->hasNoPatterns()) return; + + cout << "create patterns for block " << qPrintable(name) << endl; + if (evaluator == NULL) evaluator = new ArithmeticEvaluator(); + if (! isSourceBlock()) { + try { + createDelta(); + createConsumptionPattern(); + createProductionCounter(); + } + catch(Exception e) { + throw(e); // rethrow e + } + } + try { + createProductionPattern(); + } + catch(Exception e) { + throw(e); + } + cout << "PP of " << qPrintable(name) << endl; + QMapIterator* > it(productionPattern); + while (it.hasNext()) { + it.next(); + QList* pat = it.value(); + foreach(char c, *pat) cout << (int)c; + cout << endl; + } } -bool FunctionalBlock::createDelta() { - QString delta = implementation->getDelta(); - cout << "delta for " << qPrintable(name) << " = " << qPrintable(delta) << endl; +void FunctionalBlock::createDelta() throw(Exception) { + static QString fctName = "FunctionalBlock::createDelta()"; +#ifdef DEBUG_FCTNAME + cout << "call to " << qPrintable(fctName) << endl; +#endif - // look for parameter names - QHash vars; + QString deltaStr = implementation->getDelta(); + cout << "delta for " << qPrintable(name) << " = " << qPrintable(deltaStr) << endl; + if (deltaStr.isEmpty()) { + delta = -1; + return; + } + + // look for parameter names + double result = 0; + try { + result = evaluateExpression(deltaStr); + } + catch(Exception e) { + throw(e); + } + delta = result; + cout << "delta = " << delta << endl; +} + +void FunctionalBlock::createConsumptionPattern() throw(Exception) { + static QString fctName = "FunctionalBlock::createConsumptionPattern()"; +#ifdef DEBUG_FCTNAME + cout << "call to " << qPrintable(fctName) << endl; +#endif + + // first clear if already exists + clearConsumptionPattern(); + + lengthCP = -1; + QHash consPattern = implementation->getConsumptionPattern(); + + foreach(AbstractInterface* iface, getControlInputs()) { + FunctionalInterface* connIface = AI_TO_FUN(iface); + QString refName = connIface->getReference()->getName(); + if (! consPattern.contains(refName)) { + throw(Exception(NO_IFACE_CP,this)); + cerr << "no consumption pattern for reference interface " << qPrintable(refName) << endl; + } + QList* pattern = NULL; + try { + pattern = expandPattern(consPattern.value(refName)); + } + catch(Exception e) { + throw(e); + } + consumptionPattern.insert(connIface,pattern); + if (lengthCP == -1) { + lengthCP = pattern->size(); + } + else { + if (pattern->size() != lengthCP) { + throw(Exception(INVALID_IFACE_CP_LENGTH,this)); + } + } + } +} + +void FunctionalBlock::createProductionPattern() throw(Exception){ + static QString fctName = "FunctionalBlock::createProductionPattern()"; +#ifdef DEBUG_FCTNAME + cout << "call to " << qPrintable(fctName) << endl; +#endif + + // first clear if already exists + clearProductionPattern(); + + lengthPP = -1; + QHash prodPattern = implementation->getProductionPattern(); + + foreach(AbstractInterface* iface, getControlOutputs()) { + FunctionalInterface* connIface = AI_TO_FUN(iface); + QString refName = connIface->getReference()->getName(); + if (! prodPattern.contains(refName)) { + throw(Exception(NO_IFACE_PP,this)); + } + QList* pattern = NULL; + try { + pattern = expandPattern(prodPattern.value(refName)); + } + catch(Exception e) { + throw(e); + } + productionPattern.insert(connIface,pattern); + if (lengthPP == -1) { + lengthPP = pattern->size(); + } + else { + if (pattern->size() != lengthPP) { + throw(Exception(INVALID_IFACE_PP_LENGTH,this)); + } + } + } +} + +void FunctionalBlock::createProductionCounter() throw(Exception) { + static QString fctName = "FunctionalBlock::createProductionCounter()"; +#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) { + cout << "cont part = " << qPrintable(s) << endl; + bool ok; + double val = s.toDouble(&ok); + if (ok) { + productionCounter.append(val); + } + else if (s.at(0) == '{') { + s.remove(0,1); + s.chop(1); + QStringList gen = s.split(":"); + if (gen.size() != 3) { + throw(Exception(INVALID_IFACE_PC,this)); + } + int start = 0; + int nb = 0; + int step = 0; + for(int i=0;i<3;i++) { + double result = 0.0; + try { + result = evaluateExpression(gen.at(i)); + } + catch(Exception e) { + throw(e); + } + if (i==0) start = result; + else if (i==1) nb = result; + else if (i==2) step = result; + } + for(int j=0;j* FunctionalBlock::expandPattern(const QString& patternIn) throw(Exception) { + static QString fctName = "FunctionalBlock::expandPattern()"; +#ifdef DEBUG_FCTNAME + cout << "call to " << qPrintable(fctName) << endl; +#endif + /* 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(); + try { + patternOut->append(expandPatternRecur(p,&offset)); + } + catch(Exception e) { + throw(e); + } + + return patternOut; +} + +QString FunctionalBlock::replaceExpressions(const QString& patternIn) throw(Exception) { + + QString res = patternIn; + bool stop = false; QRegularExpression re("[$][a-zA-Z0-9_]+"); - QRegularExpressionMatchIterator matcher = re.globalMatch(delta); - while(matcher.hasNext()) { - QRegularExpressionMatch m = matcher.next(); - QString var = m.captured(0); - cout << qPrintable(var) << endl; - vars.insert(var,0.0); - } - QHashIterator iterV(vars); - while (iterV.hasNext()) { - iterV.next(); - QString var = iterV.key(); - QString paramName = var.remove(0,1); - BlockParameter* param = reference->getParameterFromName(paramName); - cout << "param = " << qPrintable(param->getStringValue()) << endl; + + 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; + + while ((*offset < patternIn.size()) && (patternIn.at(*offset) != ')')) { + + QChar c = patternIn.at(*offset); + if (c == '(') { + *offset += 1; + try { + patternOut.append(expandPatternRecur(patternIn,offset)); + } + catch(Exception e) { + throw(e); + } + } + else if (c == '0') { + patternOut.append(0); + } + else if (c == '1') { + patternOut.append(1); + } + else if (c == 'X') { + patternOut.append(-1); + } + else if (c == '{') { + *offset += 1; + QString expr = ""; + while ((*offset < patternIn.size()) && (patternIn.at(*offset) != '}')) { + expr += patternIn.at(*offset); + *offset += 1; + } + if (*offset == patternIn.size()) { + throw(Exception(INVALID_IFACE_PATTERN,this)); + } + double repeat = 0; + try { + repeat = evaluateExpression(expr); + } + catch(Exception e) { + throw(e); + } + if (repeat == 0) { + // remove the last + patternOut.removeLast(); + } + else { + // repeat just the last value in currentGroup + char last = patternOut.last(); + //cout << "repeat last char " << repeat << " times : " << (int)last << endl; + for(int i=1;i<(int)repeat;i++) { + patternOut.append(last); + } + } + } + *offset += 1; + } + + // must check if after ), there is a { + if ((*offset < patternIn.size()-1) && (patternIn.at(*offset+1) == '{')) { + *offset += 2; + QString expr = ""; + while ((*offset < patternIn.size()) && (patternIn.at(*offset) != '}')) { + expr += patternIn.at(*offset); + *offset += 1; + } + if (*offset == patternIn.size()) { + throw(Exception(INVALID_IFACE_PATTERN,this)); + } + double repeat = 0; + try { + repeat = evaluateExpression(expr); + } + catch(Exception e) { + throw(e); + } + if (repeat == 0) { + QList voidList; + return voidList; + } + else { + /* + cout << "repeat last group " << repeat << " times : "; + foreach (char c, currentGroup) cout <<(int)c; + cout << endl; + */ + QList single = patternOut; + for(int i=1;i<(int)repeat;i++) { + patternOut.append(single); + } + } + } + return patternOut; +} + +double FunctionalBlock::evaluateExpression(const QString& expression) throw(Exception) { + static QString fctName = "FunctionalBlock::evaluateExpression()"; +#ifdef DEBUG_FCTNAME + cout << "call to " << qPrintable(fctName) << endl; +#endif + + QHash vars; + evaluator->setExpression(expression); + QList varNames = evaluator->getVariableNames(); + foreach (QString name, varNames) { + QString paramName = name; + paramName.remove(0,1); + BlockParameter* param = getParameterFromName(paramName); if (param == NULL) { - cerr << "found an unknown parameter in delta"<< endl; - return false; + throw(Exception(EVAL_PARAM_UNKNOWN,this)); } - bool ok; - int val = param->getIntValue(&ok); - vars.insert(var,(double)val); + bool okVal; + int val = param->getDoubleValue(&okVal); + if (!okVal) { + throw(Exception(EVAL_PARAM_NOVALUE,this)); + } + vars.insert(name,(double)val); } - cout << "set expr " << endl; - evaluator->setExpression(delta); - cout << "set vars " << endl; + evaluator->setVariablesValue(vars); - double result = evaluator->evaluate(); - cout << "delta = " << result << endl; - - return true; + double result = 0.0; + try { + result = evaluator->evaluate(); + } + catch(int index) { + cerr << "Error at index " << index << ": " << qPrintable(evaluator->getError()) << endl; + throw(Exception(EVAL_INVALID_EXPR,this)); + } + return result; } -bool FunctionalBlock::createConsumptionPattern() { - return true; +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; + } + } -bool FunctionalBlock::createProductionPattern() { - return true; +void FunctionalBlock::createInputPattern() throw(Exception) { + static QString fctName = "FunctionalBlock::createInputPattern())"; +#ifdef DEBUG_FCTNAME + cout << "call to " << qPrintable(fctName) << endl; +#endif + + lengthIP = -1; + 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,this)); + } + if (lengthIP == -1) { + lengthIP = out->size(); + } + else { + if (out->size() < lengthIP) lengthIP = out->size(); + } + + QList* in = new QList(*out); + foreach(char c, *in) { + cout << (int)c; + } + cout << endl; + inputPattern.insert(connIface,in); + } + // search the last valid group in IP, + while(! isValidDataGroup(inputPattern,lengthIP-1)) { + //removeDataGroup(inputPattern,lengthIP-1); + lengthIP -= 1; + } } -bool FunctionalBlock::createProductionCounter() { - return true; +void FunctionalBlock::createAdmittance(int nbExec) throw(Exception) { + static QString fctName = "FunctionalBlock::createAdmittance()"; +#ifdef DEBUG_FCTNAME + cout << "call to " << qPrintable(fctName) << endl; +#endif + // firstly, copy CP in AP + QMapIterator* > iterC(consumptionPattern); + while (iterC.hasNext()) { + iterC.next(); + QList* pattern = new QList(*(iterC.value())); + admittance.insert(iterC.key(), pattern); + } + lengthAP = lengthCP; + int clock = 0; + cout << "trigger 1 at c.c. 0" << endl; + for(int i=1;i* > iterA(admittance); + while (iterA.hasNext()) { + iterA.next(); + QList* pattern = iterA.value(); + for(int i=0;isize();i++) { + if (pattern->at(i) == -1) pattern->replace(i,0); + cout << (int)(pattern->at(i)); + } + cout << endl; + } } -bool FunctionalBlock::computeOutputPattern(int nbExec) { +void FunctionalBlock::checkInputPatternCompatibility() throw(Exception) { + static QString fctName = "FunctionalBlock::checkInputPatternCompatibility()"; +#ifdef DEBUG_FCTNAME + cout << "call to " << qPrintable(fctName) << endl; +#endif + + // firstly, create input pattern + try { + createInputPattern(); + } + catch(Exception e) { + throw(e); + } + int nbExec = createTriggers(); + cout << qPrintable(name) << " will exec. " << nbExec << " times." << endl; - /* case 1: the block is a generator for which output pattern - must be computed for a nbExec following executions - */ + try { + createAdmittance(nbExec); + } + catch(Exception e) { + cout << "cannot create admittance" << endl; + throw(e); + } - if (nbExec > 0) { - foreach(AbstractInterface* iface, getControlOutputs()) { - QList pattern; - for(int i=0;igetProductionPattern(); - iface->setOutputPattern(pattern); + int clock = 0; // index in IP + int i = 0; // index in AP + while ((clock < lengthIP) && (i < lengthAP)) { + + // if AP is a valid group, search for the next valid group in IP + if (isValidDataGroup(admittance,i)) { + 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,this)); + } } + /* at that point 2 cases of compat : IP(clock) and AP(i) are equal valid group, or + are both null columns + */ + if (! samePatterns(inputPattern,clock,admittance,i)) { + cout << "AP(" << i << ") and IP(" << clock << ") are not equal" << endl; + throw(Exception(IP_AP_NOTCOMPAT,this)); // IP and AP not compatible + } + clock++; + i++; } - else { - // initialize consumption and production patterns - initConsumptionPattern(); - initProductionPattern(); - - // collect the input patterns for each input - char** inputPattern = NULL; - int idIface = 0; - inputPattern = new char*[nbConsumingPorts]; - int minLen = -1; - foreach(AbstractInterface* iface, getControlInputs()) { - QList in = iface->getConnectedFrom()->getOutputPattern(); - if (minLen == -1) { - minLen = in.size(); - } - else { - if (in.size() < minLen) minLen = in.size(); + if (clock < lengthIP) { + throw(Exception(AP_TOO_SHORT,this)); + cerr << "Abnormal case: AP is to short" << endl; + } +} + +void FunctionalBlock::computeOutputPattern(int nbExec) throw(Exception) { + static QString fctName = "FunctionalBlock::computeOutputPattern()"; +#ifdef DEBUG_FCTNAME + cout << "call to " << qPrintable(fctName) << endl; +#endif + + clearOutputPattern(); + + if (specialType != NotSpecial) { + cerr << "Abnormal case: the block is special and output pattern is computed normally" << endl; + throw(Exception(INVALID_FUNBLOCK_USE,this)); + } + + cout << "computing output pattern of " << qPrintable(name) << endl; + + // 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(); + } + catch(Exception e) { + throw(e); + } + cout << "input pattern array initialized with min. len " << lengthIP << endl; + } + + // initialize the output pattern + lengthOP = 0; + foreach(AbstractInterface* iface, getControlOutputs()) { + FunctionalInterface* connIface = AI_TO_FUN(iface); + lengthOP = lengthIP+productionPattern.value(connIface)->size(); + QList* pattern = new QList(); + for(int i=0;iappend(0); + connIface->setOutputPattern(pattern); + outputPattern.insert(connIface,pattern); + } + cout << "output pattern array initialized" << endl; + + int clock = 0; + nbExec = 0; + // search for the beginning of the first execution. + while ((clock < lengthIP) && (! isValidDataGroup(inputPattern,clock))) clock++; + cout << "found 1st exec clock: " << clock << endl; + + while (clock < lengthIP) { + // initialize counters for current execution. + int p = 0; // index in production pattern + int o = 0; // clock+o will give the clock cycle of each output group + int cip = 0; // clock+cip give the clock cycle of an input group + int ccp = 0; // ccp give a column in the consumptio pattern + int nip = 0; // number of input data groups already consumed during the current execution, used while exploring IP + int ncp = 0; // number of input data groups already consumed during the current execution, used while exploring CP + bool cannotCompleteExec = false; + for(int m=0;m 0) { - inputPattern[idIface] = new char[in.size()]; - int i = 0; - foreach(char c, in) inputPattern[idIface][i++] = c; + int gap = 0; // count the number of extra null columns + // search for PC(m) valid input group in IP + while (nip < productionCounter.at(m)) { + if (clock+cip < lengthIP) { + if (isValidDataGroup(inputPattern,clock+cip)) nip += 1; + cip += 1; + gap += 1; + } + else { + cannotCompleteExec = true; + break; + } } - else { - inputPattern[idIface] = NULL; + + if (cannotCompleteExec) break; // no need to go further since the next search of input data group will lead to go outside inputPattern + + // search for PC(m) valid input group in IP + while (ncp < productionCounter.at(m)) { + if (isValidDataGroup(consumptionPattern,ccp)) ncp += 1; + ccp += 1; + gap -= 1; } - idIface += 1; + o += gap; // to take into acocunt of extra null columns + combinePatterns(productionPattern,p,outputPattern,clock+o); + p += 1; + o += 1; + } + + if (cannotCompleteExec) break; // no need to go further since the next search of input data group will lead to go outside inputPattern + + // current exec. taken into accunt + nbExec += 1; + + // search for the next exec. + clock += 1; + nip = 0; + while ((clock < lengthIP) && (nip < delta)) { + if (isValidDataGroup(inputPattern,clock)) nip += 1; + if (nip < delta) clock += 1; + } + cout << "found exec " << nbExec << " at clock: " << clock << endl; + } + // find the last valid output data group + while(! isValidDataGroup(outputPattern,lengthOP-1)) { + removeDataGroup(outputPattern,lengthOP-1); + lengthOP -= 1; + } + + // clear input pattern + clearInputPattern(); + + setOutputPatternComputed(true); + +} + +/* + +void FunctionalBlock::computeOutputPattern(int nbExec) throw(Exception) { + static QString fctName = "FunctionalBlock::computeOutputPattern()"; +#ifdef DEBUG_FCTNAME + cout << "call to " << qPrintable(fctName) << endl; +#endif + + // 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()) { + FunctionalInterface* connIface = AI_TO_FUN(iface); + // create output pattern + QList* pp = productionPattern.value(connIface); + QList* pattern = new QList(*pp); + for(int i=1;iappend(*pp); + // assign pattern to interface + connIface->setOutputPattern(pattern); + // store it in QMap + outputPattern.insert(connIface,pattern); } - // if some patterns are not available, ens now, returning false - if (minLen == 0) { - for(int i=0;igetProductionPattern().size(); - outputPattern[idIface] = new char[lengthOP]; - memset(outputPattern[idIface],0,lengthOP); - idIface += 1; + FunctionalInterface* connIface = AI_TO_FUN(iface); + lengthOP = lengthIP+productionPattern.value(connIface)->size(); + QList* pattern = new QList(); + for(int i=0;iappend(0); + connIface->setOutputPattern(pattern); + outputPattern.insert(connIface,pattern); } - + cout << "output pattern array initialized" << endl; + int clock = 0; nbExec = 0; // search for the beginning of the first execution. - while (! isValidDataGroup(inputPattern,nbConsumingPorts,clock)) clock++; - - while (clock < minLen) { + while ((clock < lengthIP) && (! isValidDataGroup(inputPattern,clock))) clock++; + cout << "found 1st exec clock: " << clock << endl; + + while (clock < lengthIP) { // initialize counters for current execution. int p = 0; // index in production pattern int o = 0; // clock+o will give the clock cycle of each output group @@ -252,141 +1024,638 @@ bool FunctionalBlock::computeOutputPattern(int nbExec) { bool cannotCompleteExec = false; for(int m=0;m pattern; - for(int i=0;isetOutputPattern(pattern); - idIface += 1; + while(! isValidDataGroup(outputPattern,lengthOP-1)) { + removeDataGroup(outputPattern,lengthOP-1); + lengthOP -= 1; } - - // clear inputPattern and outputPattern - for(int i=0;i* >& patternSrc, int srcCol, const QMap* >& patternDest, int destCol) { + + if (patternSrc.size() != patternDest.size()) return false; + QMapIterator* > iterSrc(patternSrc); + QMapIterator* > iterDest(patternDest); + while (iterSrc.hasNext()) { + iterSrc.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::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); + QMapIterator* > iterDest(patternDest); + while (iterSrc.hasNext()) { + iterSrc.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) == -1) && (destPat->at(destCol) == 1)) return false; + if ((srcPat->at(srcCol) == 1) && (destPat->at(destCol) == -1)) return false; + } + return true; +} + +void FunctionalBlock::combinePatterns(const QMap* >& patternSrc, int srcCol, QMap* > patternDest, int destCol) { + if (patternSrc.size() != patternDest.size()) return; + QMapIterator* > iterSrc(patternSrc); + QMapIterator* > iterDest(patternDest); + while (iterSrc.hasNext()) { + iterSrc.next(); + iterDest.next(); + QList* srcPat = iterSrc.value(); + QList* destPat = iterDest.value(); + if (srcCol >= srcPat->size()) return; + if (destCol >= destPat->size()) return; + if ((srcPat->at(srcCol) == -1) && (destPat->at(destCol) == 1)) return; + if ((srcPat->at(srcCol) == 1) && (destPat->at(destCol) == -1)) return; + destPat->replace(destCol,destPat->at(destCol) | srcPat->at(srcCol)); + } +} + +void FunctionalBlock::appendToPattern(const QMap* >& patternSrc, int srcCol, QMap* > patternDest, int nbCols) { + if (patternSrc.size() != patternDest.size()) return; + QMapIterator* > iterSrc(patternSrc); + QMapIterator* > iterDest(patternDest); + while (iterSrc.hasNext()) { + iterSrc.next(); + iterDest.next(); + QList* srcPat = iterSrc.value(); + QList* destPat = iterDest.value(); + int i=0; + while ((srcCol+i < srcPat->size()) && (iappend(srcPat->at(srcCol+i)); + i++; } - delete [] inputPattern; - for(int i=0;i *> &pattern, int offset) { + QMapIterator* > iterSrc(pattern); + while (iterSrc.hasNext()) { + iterSrc.next(); + QList* srcPat = iterSrc.value(); + if (offset < srcPat->size()) { + srcPat->removeAt(offset); } - delete [] outputPattern; } - return true; } -bool FunctionalBlock::isValidDataGroup(char** pattern, int nbPorts, int clock) { - - for(int i=0;i *> &pattern, int offset) { + QMapIterator* > iterSrc(pattern); + while (iterSrc.hasNext()) { + iterSrc.next(); + QList* srcPat = iterSrc.value(); + if (offset < srcPat->size()) { + srcPat->insert(offset,0); + } } - return false; } -void FunctionalBlock::combinePatterns(char** patternSrc, int srcCol, char** patternDest, int destCol, int nbCols, int nbPorts ) { +bool FunctionalBlock::isValidDataGroup(const QMap *> &pattern, int offset) { + QMapIterator* > iterSrc(pattern); + while (iterSrc.hasNext()) { + iterSrc.next(); + QList* srcPat = iterSrc.value(); + if (offset >= srcPat->size()) return false; + if (srcPat->at(offset) == 1) return true; + } + return false; +} + +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()) { + iterSrc.next(); + QList* srcPat = iterSrc.value(); + if (offset >= srcPat->size()) return false; + if (srcPat->at(offset) != -1) return false; + } + return true; +} + +void FunctionalBlock::clearConsumptionPattern() { + QMapIterator* > iterP(consumptionPattern); + while (iterP.hasNext()) { + iterP.next(); + QList* pattern = iterP.value(); + if (pattern != NULL) delete pattern; + } + consumptionPattern.clear(); + lengthCP = -1; +} + +void FunctionalBlock::clearProductionPattern() { + QMapIterator* > iterP(productionPattern); + while (iterP.hasNext()) { + iterP.next(); + QList* pattern = iterP.value(); + if (pattern != NULL) delete pattern; + } + productionPattern.clear(); + lengthPP = -1; +} + +void FunctionalBlock::clearInputPattern() { - for (int i=0;i* > iterI(inputPattern); + while (iterI.hasNext()) { + iterI.next(); + QList* pattern = iterI.value(); + if (pattern != NULL) delete pattern; + } + inputPattern.clear(); + 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 + but not necessary completed. + */ + if (delta <= 0) return 0; + int offset = 0; + // search for the first exec. + while ((offset < lengthIP) && (! isValidDataGroup(inputPattern,offset))) offset++; + if (offset == lengthIP) return 0; + triggers.append(offset); + int nbGroup = 0; + for(int i = offset;i FunctionalBlock::getExternalResources() { + + BlockImplementation* impl = reference->getImplementations().at(0); // for now only take first impl available + QList list = impl->getResources(); + foreach(QString s, list) { + cout << qPrintable(s) << " "; } - + cout << endl; + + return list; } -void FunctionalBlock::clearConsumptionPattern() { - if (consumptionPattern == NULL) return; + +void FunctionalBlock::generateVHDL(const QString& path) throw(Exception){ + + BlockImplementation* impl = reference->getImplementations().at(0); // for now only take first impl available + + QFile implFile(impl->getXmlFile()); + + // reading in into QDomDocument + QDomDocument document("implFile"); + + if (!implFile.open(QIODevice::ReadOnly)) { + throw(Exception(IMPLFILE_NOACCESS)); + } + if (!document.setContent(&implFile)) { + implFile.close(); + throw(Exception(IMPLFILE_NOACCESS)); + } + implFile.close(); + + bool genController = false; + QString coreFile = ""; + QString controllerFile = ""; + + if (reference->isWBConfigurable()) { + genController = true; + controllerFile = path; + controllerFile += "/"; + controllerFile.append(name); + controllerFile.append("_ctrl.vhd"); + } + else { + controllerFile = "nofile.vhd"; + } + coreFile = path; + coreFile += "/"; + coreFile.append(name); + coreFile.append(".vhd"); + + QFile vhdlCore(coreFile); + QFile vhdlController(controllerFile); + + if (!vhdlCore.open(QIODevice::WriteOnly)) { + throw(Exception(VHDLFILE_NOACCESS)); + } + + if (genController) { + if (!vhdlController.open(QIODevice::WriteOnly)) { + throw(Exception(VHDLFILE_NOACCESS)); + } + } + QTextStream outCore(&vhdlCore); + QTextStream outController; + if (genController) { + outController.setDevice(&vhdlController); + } + + try { + //Get the root element + QDomElement impl = document.documentElement(); + QDomElement eltComments = impl.firstChildElement("comments"); + generateComments(outCore,eltComments, coreFile); + QDomElement eltLibs = eltComments.nextSiblingElement("libraries"); + generateLibraries(outCore, eltLibs); + generateEntity(outCore, genController); + QDomElement eltArch = eltLibs.nextSiblingElement("architecture"); + generateArchitecture(outCore, eltArch ); + if (genController) { + generateController(outController); + } + } + catch(Exception err) { + throw(err); + } + + vhdlCore.close(); + vhdlController.close(); - for(int i=0;igetDescription() << endl; + out << "--" << endl; + QDomElement eltNote = eltLog.nextSiblingElement("notes"); + QDomElement note = eltNote.firstChildElement(); + QString noteTxt = note.text(); + out << "-- Notes :\n"< in = iface->getConsumptionPattern(); - lengthCP = in.size(); // normally, all inputs have the same lenght for CP - consumptionPattern[idIface] = new char[lengthCP]; - int i = 0; - foreach(char c, in) consumptionPattern[idIface][i++] = c; - idIface += 1; + //QList listParams = reference->getParameters(); + QList listInputs = getInputs(); + QList listOutputs = getOutputs(); + QList listBidirs = getBidirs(); + + // Generation of the generics + QList listGenerics = getGenericParameters(); + if ((!listGenerics.isEmpty()) || (hasController)) { + out << indent << " generic (" << endl; + if (hasController) { + out << indent << " wb_data_width : integer = 16;" << endl; + out << indent << " wb_addr_width : integer = 12"; + if (!listGenerics.isEmpty()) out << indent << ";"; + out << endl; + } + for(i=0;itoVHDL(BlockParameter::Entity, 0) << endl; + } + out << indent << " " << listGenerics.at(i)->toVHDL(BlockParameter::Entity,BlockParameter::NoComma) << endl; + + out << indent << " );" << endl; } + + out << indent << " port (" << endl; + + QString ports = ""; + QTextStream outPorts(&ports); + + // Generation of the clk & rst signals + outPorts << indent << " -- clk/rst" << endl; + foreach(AbstractInterface* iface, listInputs) { + if(iface->getPurpose() == AbstractInterface::Clock || iface->getPurpose() == AbstractInterface::Reset) { + outPorts << indent << " " << iface->getName() << " : in std_logic;" << endl; + } + } + foreach(AbstractInterface* iface, listOutputs) { + if(iface->getPurpose() == AbstractInterface::Clock || iface->getPurpose() == AbstractInterface::Reset) { + outPorts << indent << " " << iface->getName() << " : out std_logic;" << endl; + } + } + + if (hasController) { + // Generation of the wishbone signals + outPorts << indent << " -- registers r/w via wishbone" << endl; + QList listWB = reference->getWishboneParameters(); + for(i=0;itoVHDL(BlockParameter::Entity, 0) << endl; + } + outPorts << indent << " " << listWB.at(i)->toVHDL(BlockParameter::Entity,BlockParameter::NoComma) << endl; + } + + // Generation of the data/control signals + + QList listIface = getInterfaces(AbstractInterface::Input, AbstractInterface::Data); + if (listIface.size()>0) { + outPorts << indent << " -- input data ports" << endl; + foreach(AbstractInterface* iface, listIface) { + outPorts << indent << " " << iface->toVHDL(AbstractInterface::Entity, 0) << endl; + } + } + listIface = getInterfaces(AbstractInterface::Input, AbstractInterface::Control); + if (listIface.size()>0) { + outPorts << indent << " -- input control ports" << endl; + foreach(AbstractInterface* iface, listIface) { + outPorts << indent << " " << iface->toVHDL(AbstractInterface::Entity, 0) << endl; + } + } + listIface = getInterfaces(AbstractInterface::Output, AbstractInterface::Data); + if (listIface.size()>0) { + outPorts << indent << " -- output data ports" << endl; + foreach(AbstractInterface* iface, listIface) { + outPorts << indent << " " << iface->toVHDL(AbstractInterface::Entity, 0) << endl; + } + } + listIface = getInterfaces(AbstractInterface::Output, AbstractInterface::Control); + if (listIface.size()>0) { + outPorts << indent << " -- output control ports" << endl; + foreach(AbstractInterface* iface, listIface) { + outPorts << indent << " " << iface->toVHDL(AbstractInterface::Entity, 0) << endl; + } + } + listIface = getInterfaces(AbstractInterface::InOut, AbstractInterface::Data); + if (listIface.size()>0) { + outPorts << indent << " -- bidirs data ports" << endl; + foreach(AbstractInterface* iface, listIface) { + outPorts << indent << " " << iface->toVHDL(AbstractInterface::Entity, 0) << endl; + } + } + + ports.chop(2); + ports += "\n"; + out << ports; + out << indent << " );" << endl << endl; + } -void FunctionalBlock::initProductionPattern() { - if (productionPattern != NULL) clearProductionPattern(); +void FunctionalBlock::generateArchitecture(QTextStream& out, QDomElement &elt ) throw(Exception) { + QRegularExpression rxPort("@\\{([a-zA-Z0-9_]+)\\}"); + QString expr; + QString code = elt.text(); + //cout << qPrintable(code) << endl; + out << "architecture rtl of " << name << " is" << endl; + + QStringList listLine = code.split("\n"); + for(int i =0; i < listLine.size(); i++) { + QString line = listLine.at(i).simplified(); + + /* + if(listLine.at(i).contains(QRegularExpression("@foreach{"))) { + while(listLine.at(i).compare("@endforeach") != -1) { + expr = expr + listLine.at(i) + '\n'; + i++; + } + expr = expr + listLine.at(i); + out << evalComplex(expr, 1) << '\n'; + } + if(listLine.at(i).contains(QRegularExpression("@caseeach{"))) { + while(listLine.at(i).compare("@endcaseeach") != -1) { + expr = expr + listLine.at(i) + '\n'; + i++; + } + expr = expr + listLine.at(i); + out << evalComplex(expr, 2) << '\n'; + } +*/ + if(line.contains("@{")) { + QMap modifs; + //cout << qPrintable(line) << endl; + QRegularExpressionMatchIterator matchPort = rxPort.globalMatch(line); + while(matchPort.hasNext()) { + QRegularExpressionMatch m = matchPort.next(); + QString refName = m.captured(1); + AbstractInterface* refIface = reference->getIfaceFromName(refName); + QString funName = getIfaceUserName(refIface); + if (!funName.isEmpty()) { + modifs.insert(m.captured(0),funName); + //cout << "replace " << qPrintable(refIface->getName()) << " by " << qPrintable(funIface->getName()) << endl; + } + } + QMapIterator iterM(modifs); + while(iterM.hasNext()) { + iterM.next(); + QString oldName = iterM.key(); + QString newName = iterM.value(); + line.replace(oldName,newName); + } + } + out << line << endl; + } + + out << "end rtl;" << endl; +} + +void FunctionalBlock::generateController(QTextStream &out) throw(Exception) { - nbProducingPorts = getControlOutputs().size(); - int idIface = 0; - productionPattern = new char*[nbProducingPorts]; - foreach(AbstractInterface* iface, getControlOutputs()) { - - QList in = iface->getProductionPattern(); - lengthPP = in.size(); // normally, all inputs have the same lenght for PP - productionPattern[idIface] = new char[lengthPP]; - int i = 0; - foreach(char c, in) productionPattern[idIface][i++] = c; - idIface += 1; +} + +QString FunctionalBlock::getIfaceUserName(AbstractInterface* refIface) { + + if (! refIface->isReferenceInterface()) return ""; + + AbstractInterface* funcIface = NULL; + + if (refIface->getDirection() == AbstractInterface::Input) { + foreach(AbstractInterface* iface, getInputs()) { + FunctionalInterface* fi = AI_TO_FUN(iface); + if (fi->getReference() == refIface) { + funcIface = iface; + break; + } + } + } + else if (refIface->getDirection() == AbstractInterface::Output) { + foreach(AbstractInterface* iface, getOutputs()) { + FunctionalInterface* fi = AI_TO_FUN(iface); + if (fi->getReference() == refIface) { + funcIface = iface; + break; + } + } + } + else if (refIface->getDirection() == AbstractInterface::InOut) { + foreach(AbstractInterface* iface, getBidirs()) { + FunctionalInterface* fi = AI_TO_FUN(iface); + if (fi->getReference() == refIface) { + funcIface = iface; + break; + } + } } + if (funcIface == NULL) return ""; + + return funcIface->getName(); } +