X-Git-Url: https://bilbo.iut-bm.univ-fcomte.fr/and/gitweb/blast.git/blobdiff_plain/4cf57e6db08da791233d75237f62e74bc88dd427..3fb762e7042d9b4a1cf78556ad9ed7f117cc53ba:/FunctionalBlock.cpp?ds=sidebyside diff --git a/FunctionalBlock.cpp b/FunctionalBlock.cpp index 91f4e03..0fb38c3 100644 --- a/FunctionalBlock.cpp +++ b/FunctionalBlock.cpp @@ -8,7 +8,7 @@ #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; @@ -29,6 +29,11 @@ FunctionalBlock::FunctionalBlock(GroupBlock *_parent, ReferenceBlock *_reference lengthPP = -1; delta = -1; evaluator = NULL; + + if (createIfaces) { + populate(); + } + } FunctionalBlock::~FunctionalBlock() { @@ -60,7 +65,7 @@ bool FunctionalBlock::isFunctionalBlock() { return true; } -bool FunctionalBlock::isSourceBlock() { +bool FunctionalBlock::isStimuliBlock() { if (parent == NULL) return true; return false; } @@ -77,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 @@ -90,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; @@ -110,7 +128,6 @@ void FunctionalBlock::populate() { } } - QString FunctionalBlock::getReferenceXmlFile() { return ((ReferenceBlock *)reference)->getXmlFile(); } @@ -124,10 +141,12 @@ void FunctionalBlock::createPatterns() throw(Exception) { #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 (! isGeneratorBlock()) { + if (! isSourceBlock()) { try { createDelta(); createConsumptionPattern(); @@ -414,12 +433,17 @@ QList FunctionalBlock::expandPatternRecur(const QString& patternIn, int *o 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); + 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; @@ -443,15 +467,21 @@ QList FunctionalBlock::expandPatternRecur(const QString& patternIn, int *o 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; + cout << endl; */ - QList single = patternOut; - for(int i=1;i<(int)repeat;i++) { - patternOut.append(single); - } + QList single = patternOut; + for(int i=1;i<(int)repeat;i++) { + patternOut.append(single); + } + } } return patternOut; } @@ -649,9 +679,7 @@ void FunctionalBlock::createInputPattern() throw(Exception) { } // get the precursor output pattern QList* out = connIface->getConnectedFrom()->getOutputPattern(); - - ConnectedInterface* assoIface = AI_TO_CON(connIface->getAssociatedIface()); - AbstractInputModifier* modifier = assoIface->getInputModifier(); + AbstractInputModifier* modifier = connIface->getInputModifier(); // check if the input is modified if (modifier != NULL) { @@ -815,127 +843,116 @@ void FunctionalBlock::computeOutputPattern(int nbExec) throw(Exception) { #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); - } + + clearOutputPattern(); + + if (specialType != NotSpecial) { + cerr << "Abnormal case: the block is special and output pattern is computed normally" << endl; + throw(Exception(INVALID_FUNBLOCK_USE,this)); } - else { - 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; + 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(); } - - // 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); + catch(Exception e) { + throw(e); } - 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;msize(); + 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* > 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()) { @@ -1274,3 +1305,357 @@ int FunctionalBlock::createTriggers() { } return triggers.size(); } + +QList 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::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(); + + } + +void FunctionalBlock::generateComments(QTextStream& out, QDomElement &elt, QString coreFile) throw(Exception) { + + for(int i = 0; i < 50; i++) { + out << "--"; + } + out << "\n--" << endl; + QString fileName = coreFile; + out << "-- File : " << fileName << endl; + out << "--" << endl; + QDomElement eltAuthor = elt.firstChildElement("author"); + QString firstName = eltAuthor.attribute("firstname",""); + QString lastName = eltAuthor.attribute("lastname",""); + QString mail = eltAuthor.attribute("mail",""); + out << "-- Author(s) : "<getDescription() << endl; + out << "--" << endl; + QDomElement eltNote = eltLog.nextSiblingElement("notes"); + QDomElement note = eltNote.firstChildElement(); + QString noteTxt = note.text(); + out << "-- Notes :\n"< 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::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) { + +} + +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(); +} +