1 #include "BlockImplementation.h"
\r
3 #include "FunctionalBlock.h"
\r
4 #include "ReferenceBlock.h"
\r
5 #include "ReferenceInterface.h"
\r
6 #include "FunctionalInterface.h"
\r
7 #include "BlockParameter.h"
\r
8 #include <QHashIterator>
\r
11 BlockImplementation::BlockImplementation(const QString& _xmlFile) {
\r
13 productionCounter = "";
\r
16 evaluator = new ArithmeticEvaluator;
\r
17 evaluator->setVariableMarkers("@$");
\r
20 BlockImplementation::BlockImplementation(const QString& _xmlFile, const QString &_referenceXml, const QString &_referenceMd5) {
\r
21 xmlFile = _xmlFile;
\r
22 productionCounter = "";
\r
24 referenceXml = _referenceXml;
\r
25 referenceMd5 = _referenceMd5;
\r
28 void BlockImplementation::loadPatterns(QDomElement& root) throw(Exception) {
\r
30 QDomNodeList patternNode = root.elementsByTagName("patterns");
\r
32 if (patternNode.isEmpty()) {
\r
33 cout << "impl has no patterns" << endl;
\r
37 QDomElement patternElt = patternNode.at(0).toElement();
\r
39 QDomElement eltDelta = patternElt.firstChildElement("delta");
\r
40 delta = eltDelta.attribute("value","none");
\r
42 QDomElement eltCons = eltDelta.nextSiblingElement("consumption");
\r
44 QDomNodeList listNodeInput = eltCons.elementsByTagName("input");
\r
45 for(int i=0; i<listNodeInput.size(); i++) {
\r
46 QDomNode node = listNodeInput.at(i);
\r
47 QDomElement elt = node.toElement();
\r
48 QString nameStr = elt.attribute("name","none");
\r
49 if (nameStr == "none") throw(Exception(IMPLFILE_CORRUPTED));
\r
50 QString patternStr = elt.attribute("pattern","none");
\r
51 consumptionPattern.insert(nameStr,patternStr);
\r
54 QDomElement eltProd = eltCons.nextSiblingElement("production");
\r
56 productionCounter = eltProd.attribute("counter","none");
\r
57 QDomNodeList listNodeOutput = eltProd.elementsByTagName("output");
\r
58 for(int i=0; i<listNodeOutput.size(); i++) {
\r
59 QDomNode node = listNodeOutput.at(i);
\r
60 QDomElement elt = node.toElement();
\r
61 QString nameStr = elt.attribute("name","none");
\r
62 if (nameStr == "none") throw(Exception(IMPLFILE_CORRUPTED));
\r
63 QString patternStr = elt.attribute("pattern","none");
\r
64 productionPattern.insert(nameStr,patternStr);
\r
66 cout << "patterns summary:" << endl;
\r
67 QHashIterator<QString,QString> iterP(productionPattern);
\r
68 while (iterP.hasNext()) {
\r
70 cout << qPrintable(iterP.key()) << " -> " << qPrintable(iterP.value()) << endl;
\r
72 cout << "impls patterns read correctly" << endl;
\r
75 bool BlockImplementation::checkPatterns() {
\r
78 if (reference == NULL) {
\r
79 cout << "no ref. while checking patterns of implementation " << endl;
\r
83 AbstractInterface* iface;
\r
84 QHashIterator<QString,QString> iterI(consumptionPattern);
\r
85 while (iterI.hasNext()) {
\r
87 iface = reference->getIfaceFromName(iterI.key());
\r
88 if (iface == NULL) {
\r
89 cout << "cannot found an input ref. iface for impl. iface " << qPrintable(iterI.key()) << endl;
\r
93 QHashIterator<QString,QString> iterO(productionPattern);
\r
94 while (iterO.hasNext()) {
\r
96 iface = reference->getIfaceFromName(iterO.key());
\r
97 if (iface == NULL) {
\r
98 cout << "cannot found an output ref. iface for impl. iface " << qPrintable(iterI.key()) << endl;
\r
105 void BlockImplementation::generateVHDL(FunctionalBlock* _block, const QString &path) throw(Exception) {
\r
109 QFile implFile(xmlFile);
\r
111 // reading in into QDomDocument
\r
112 QDomDocument document("implFile");
\r
114 if (!implFile.open(QIODevice::ReadOnly)) {
\r
115 throw(Exception(IMPLFILE_NOACCESS));
\r
117 if (!document.setContent(&implFile)) {
\r
119 throw(Exception(IMPLFILE_NOACCESS));
\r
123 bool genController = false;
\r
124 QString coreFile = "";
\r
125 QString controllerFile = "";
\r
127 if (reference->isWBConfigurable()) {
\r
128 genController = true;
\r
129 controllerFile = path;
\r
130 controllerFile += "/";
\r
131 controllerFile.append(block->getName());
\r
132 controllerFile.append("_ctrl.vhd");
\r
135 controllerFile = "nofile.vhd";
\r
139 coreFile.append(block->getName());
\r
140 coreFile.append(".vhd");
\r
142 QFile vhdlCore(coreFile);
\r
143 QFile vhdlController(controllerFile);
\r
145 if (!vhdlCore.open(QIODevice::WriteOnly)) {
\r
146 throw(Exception(VHDLFILE_NOACCESS));
\r
149 if (genController) {
\r
150 if (!vhdlController.open(QIODevice::WriteOnly)) {
\r
151 throw(Exception(VHDLFILE_NOACCESS));
\r
154 QTextStream outCore(&vhdlCore);
\r
155 QTextStream outController;
\r
156 if (genController) {
\r
157 outController.setDevice(&vhdlController);
\r
163 //Get the root element
\r
164 QDomElement impl = document.documentElement();
\r
165 QDomElement eltComments = impl.firstChildElement("comments");
\r
166 generateComments(eltComments, coreFile, outCore);
\r
167 QDomElement eltLibs = eltComments.nextSiblingElement("libraries");
\r
168 generateLibraries(eltLibs, outCore);
\r
169 generateEntity(outCore, genController);
\r
170 QDomElement eltArch = eltLibs.nextSiblingElement("architecture");
\r
171 generateArchitecture(eltArch, outCore);
\r
172 if (genController) {
\r
173 generateController(outController);
\r
176 catch(Exception err) {
\r
181 vhdlController.close();
\r
184 // This function generates the comments part of the VHDL document
\r
185 void BlockImplementation::generateComments(QDomElement &elt, QString coreFile, QTextStream& out) throw(Exception) {
\r
187 for(int i = 0; i < 50; i++) {
\r
190 out << "\n--" << endl;
\r
191 QString fileName = coreFile;
\r
192 out << "-- File : " << fileName << endl;
\r
193 out << "--" << endl;
\r
194 QDomElement eltAuthor = elt.firstChildElement("author");
\r
195 QString firstName = eltAuthor.attribute("firstname","");
\r
196 QString lastName = eltAuthor.attribute("lastname","");
\r
197 QString mail = eltAuthor.attribute("mail","");
\r
198 out << "-- Author(s) : "<<firstName+" "<<lastName<<" ("<<mail<<")" << endl;
\r
199 out << "--" << endl;
\r
200 QDomElement eltDate = eltAuthor.nextSiblingElement("date");
\r
201 QString crea = eltDate.attribute("creation","");
\r
202 out << "-- Creation Date : "<<crea<< endl;
\r
203 out << "--" << endl;
\r
204 QDomElement eltRelated = eltDate.nextSiblingElement("related_files");
\r
205 QString relateds = eltRelated.attribute("list","");
\r
206 out << "-- Related files :\n"<<relateds<<endl;
\r
207 out << "--" << endl;
\r
208 QDomElement eltDesc = eltRelated.nextSiblingElement("description");
\r
209 QDomElement desc = eltDesc.firstChildElement();
\r
210 QString descTxt = desc.text();
\r
211 out << "-- Decription :\n"<<descTxt<<endl;
\r
212 out << "--" << endl;
\r
213 QDomElement eltNote = eltDesc.nextSiblingElement("description");
\r
214 QDomElement note = eltNote.firstChildElement();
\r
215 QString noteTxt = note.text();
\r
216 out << "-- Note :\n"<<noteTxt<<endl;
\r
217 out << "--" << endl;
\r
218 for(int i = 0; i < 50; i++) {
\r
221 out << endl << endl;
\r
224 // This function generates the library part of the VHDL document
\r
225 void BlockImplementation::generateLibraries(QDomElement &elt, QTextStream& out) throw(Exception) {
\r
227 QDomNodeList listLib = elt.elementsByTagName("library");
\r
228 for(int i = 0; i < listLib.length(); i++) {
\r
229 QDomNode nodeLib = listLib.item(i);
\r
230 QDomElement eltLib = nodeLib.toElement();
\r
231 QString nameLib = eltLib.attribute("name","none");
\r
232 out << "library " << nameLib << ";" << endl;
\r
233 QDomNodeList listPack = eltLib.elementsByTagName("package");
\r
234 for(int j = 0; j < listPack.length(); j++) {
\r
235 QDomNode nodePack = listPack.item(j);
\r
236 QDomElement eltPack = nodePack.toElement();
\r
237 QString namePack = eltPack.attribute("name","none");
\r
238 QString usePack = eltPack.attribute("use","none");
\r
239 out << "use " << nameLib << "." << namePack << "." << usePack << endl;
\r
245 // This function generates the entity part of the VHDL document
\r
246 void BlockImplementation::generateEntity(QTextStream& out, bool hasController) throw(Exception) {
\r
249 nameEnt = block->getName();
\r
250 //QList<BlockParameter*> listParams = reference->getParameters();
\r
251 QList<AbstractInterface*> listInputs = block->getInputs();
\r
252 QList<AbstractInterface*> listOutputs = block->getOutputs();
\r
253 QList<AbstractInterface*> listBidirs = block->getBidirs();
\r
254 QString typePort, namePort;
\r
256 out << "entity " << nameEnt << " is" << endl;
\r
259 /* TODO : rewrite the generation to take into acocunt the new object hierarchy */
\r
261 // Generation of the generics
\r
262 QList<BlockParameter*> listGenerics = block->getGenericParameters();
\r
263 if ((!listGenerics.isEmpty()) || (hasController)) {
\r
264 out << " generic (" << endl;
\r
265 if (hasController) {
\r
266 out << " wb_data_width : integer = 16;" << endl;
\r
267 out << " wb_addr_width : integer = 12";
\r
268 if (!listGenerics.isEmpty()) out << ";";
\r
271 for(i=0;i<listGenerics.size()-1;i++) {
\r
272 out << " " << listGenerics.at(i)->toVHDL(BlockParameter::Entity, 0) << endl;
\r
274 out << " " << listGenerics.at(i)->toVHDL(BlockParameter::Entity,BlockParameter::NoComma) << endl;
\r
276 out << " );" << endl;
\r
279 out << " port (" << endl;
\r
281 // Generation of the clk & rst signals
\r
282 out << " -- clk/rst" << endl;
\r
283 foreach(AbstractInterface* iface, listInputs) {
\r
284 if(iface->getPurpose() == AbstractInterface::Clock || iface->getPurpose() == AbstractInterface::Reset) {
\r
285 out << " " << iface->getName() << " : in std_logic;" << endl;
\r
289 if (hasController) {
\r
290 // Generation of the wishbone signals
\r
291 out << " -- registers r/w via wishbone" << endl;
\r
292 QList<BlockParameter*> listWB = reference->getWishboneParameters();
\r
293 for(i=0;i<listWB.size()-1;i++) {
\r
294 out << " " << listWB.at(i)->toVHDL(BlockParameter::Entity, 0) << endl;
\r
296 out << " " << listWB.at(i)->toVHDL(BlockParameter::Entity,BlockParameter::NoComma) << endl;
\r
301 foreach(AbstractInterface* iface, block->getInterfaces()) {
\r
302 if((iface->getPurpose() == AbstractInterface::Data)||(iface->getPurpose() == AbstractInterface::Control)) count++;
\r
304 // Generation of the data/control signals
\r
309 foreach(AbstractInterface* iface, listInputs) {
\r
310 if(iface->getPurpose() == AbstractInterface::Data) {
\r
312 out << " -- input data ports" << endl;
\r
316 if (count == 0) flag = AbstractInterface::NoComma;
\r
317 out << " " << iface->toVHDL(AbstractInterface::Entity, flag) << endl;
\r
321 foreach(AbstractInterface* iface, listInputs) {
\r
322 if(iface->getPurpose() == AbstractInterface::Control) {
\r
324 out << " -- input control ports" << endl;
\r
328 if (count == 0) flag = AbstractInterface::NoComma;
\r
329 out << " " << iface->toVHDL(AbstractInterface::Entity, flag) << endl;
\r
333 foreach(AbstractInterface* iface, listOutputs) {
\r
334 if(iface->getPurpose() == AbstractInterface::Data) {
\r
336 out << " -- output data ports" << endl;
\r
340 if (count == 0) flag = AbstractInterface::NoComma;
\r
341 out << " " << iface->toVHDL(AbstractInterface::Entity, flag) << endl;
\r
345 foreach(AbstractInterface* iface, listOutputs) {
\r
346 if(iface->getPurpose() == AbstractInterface::Control) {
\r
348 out << " -- output control ports" << endl;
\r
352 if (count == 0) flag = AbstractInterface::NoComma;
\r
353 out << " " << iface->toVHDL(AbstractInterface::Entity, flag) << endl;
\r
357 foreach(AbstractInterface* iface, listBidirs) {
\r
358 if(iface->getPurpose() == AbstractInterface::Data) {
\r
360 out << " -- bidirs data ports" << endl;
\r
364 if (count == 0) flag = AbstractInterface::NoComma;
\r
365 out << " " << iface->toVHDL(AbstractInterface::Entity, flag) << endl;
\r
368 out << " );" << endl << endl;
\r
369 out << "end " << nameEnt << ";" << endl << endl;
\r
372 // This function generates the architecture part of the VHDL document
\r
373 void BlockImplementation::generateArchitecture(QDomElement &elt, QTextStream& out) throw(Exception) {
\r
376 QString code = elt.text();
\r
377 cout << qPrintable(code) << endl;
\r
378 out << "architecture rtl of " << nameEnt << " is" << endl;
\r
380 QStringList listLine = code.split("\n");
\r
381 for(int i =0; i < listLine.size(); i++) {
\r
382 QString line = listLine.at(i).simplified();
\r
385 if(listLine.at(i).contains(QRegularExpression("@foreach{"))) {
\r
386 while(listLine.at(i).compare("@endforeach") != -1) {
\r
387 expr = expr + listLine.at(i) + '\n';
\r
390 expr = expr + listLine.at(i);
\r
391 out << evalComplex(expr, 1) << '\n';
\r
393 if(listLine.at(i).contains(QRegularExpression("@caseeach{"))) {
\r
394 while(listLine.at(i).compare("@endcaseeach") != -1) {
\r
395 expr = expr + listLine.at(i) + '\n';
\r
398 expr = expr + listLine.at(i);
\r
399 out << evalComplex(expr, 2) << '\n';
\r
402 if(line.contains("@{")) {
\r
403 out << line << endl;
\r
408 void BlockImplementation::generateController(QTextStream &out) throw(Exception) {
\r
411 QString BlockImplementation::eval(QString line, QTextStream& out) {
\r
412 QString res, s, begLine, endLine, expr;
\r
413 evaluator->setExpression(line);
\r
414 QRegExp *rxString = new QRegExp("(.*)@{(.*)}(.*)");
\r
415 QRegExp *rxValue = new QRegExp("(.*)@val{(.*)}(.*)");
\r
416 QRegExp *rxExpr = new QRegExp(".*@eval{(.*)}.*");
\r
418 int nbAt = line.count('@');
\r
420 for(int i = 0; i < line.size(); i++) {
\r
421 if(rxString->indexIn(line)) {
\r
422 begLine = rxString->cap(1);
\r
423 s = rxString->cap(2);
\r
424 endLine = rxString->cap(3);
\r
425 res = begLine + evalString(s) + endLine + '\n';
\r
429 for(int i = 0; i < line.size(); i++) {
\r
430 if(rxValue->indexIn(line)) {
\r
431 begLine = rxValue->cap(1);
\r
432 s = rxValue->cap(2);
\r
433 endLine = rxValue->cap(3);
\r
434 res = begLine + evalValue(s) + endLine + '\n';
\r
438 for(int i = 0; i < line.size(); i++) {
\r
439 if(rxExpr->indexIn(line)) {
\r
440 expr = rxExpr->cap(1);
\r
441 if(expr.count('@') == 0) {
\r
442 evaluator->setExpression(expr);
\r
443 s = QString::number(evaluator->evaluate());
\r
445 res = begLine + s + endLine + '\n';
\r
453 QString BlockImplementation::evalComplex(QString line, int id) {
\r
454 QString res, s, begLine, endLine, expr;
\r
455 QRegExp *rxString = new QRegExp("(.*)@{(.*)}(.*)");
\r
456 QRegExp *rxValue = new QRegExp("(.*)@val{(.*)}(.*)");
\r
457 QRegExp *rxExpr = new QRegExp(".*@eval{(.*)}.*");
\r
458 QRegExp *rxFor = new QRegExp("@foreach{.*}(@{.*})(.*)@endforeach");
\r
459 QRegExp *rxCase = new QRegExp("@caseeach{.*,(.*),(.*)}(@{.*})(.*)@endcaseeach");
\r
460 QRegExp *rxCaseDown = new QRegExp("@#-:(.*)");
\r
461 QRegExp *rxCaseUp = new QRegExp("@#:(.*)");
\r
462 evaluator->setExpression(line);
\r
464 int nbAt = line.count('@') - 2;
\r
466 for(int i = 0; i < line.size(); i++) {
\r
467 if(rxString->indexIn(line)) {
\r
468 begLine = rxString->cap(1);
\r
469 s = rxString->cap(2);
\r
470 endLine = rxString->cap(3);
\r
471 if(evalStringComplex(s)->size() == 0)
\r
472 line = begLine + evalString(s) + endLine;
\r
476 for(int i = 0; i < line.size(); i++) {
\r
477 if(rxValue->indexIn(line)) {
\r
478 begLine = rxValue->cap(1);
\r
479 s = rxValue->cap(2);
\r
480 endLine = rxValue->cap(3);
\r
481 line = begLine + evalValue(s) + endLine;
\r
485 for(int i = 0; i < line.size(); i++) {
\r
486 if(rxExpr->indexIn(line)) {
\r
487 expr = rxExpr->cap(1);
\r
488 if(expr.count('@') == 0) {
\r
489 evaluator->setExpression(expr);
\r
490 s = QString::number(evaluator->evaluate());
\r
492 res = begLine + s + endLine + '\n';
\r
499 if(rxFor->indexIn(line)) {
\r
500 QString intName, instruc;
\r
501 intName = rxFor->cap(1);
\r
502 instruc = rxFor->cap(2);
\r
503 QList<AbstractInterface*> *intList = evalStringComplex(intName);
\r
504 if(intList->size() != 0) {
\r
505 for(int i = 0; i < intList->size(); i++) {
\r
506 res = intList->at(i)->getName() + instruc + '\n';
\r
513 if(rxCase->indexIn(line)) {
\r
514 QString intName, sigName, cases, instruc;
\r
516 sigName = rxCase->cap(1);
\r
517 cases = rxCase->cap(2);
\r
518 intName = rxCase->cap(3);
\r
519 instruc = rxCase->cap(4);
\r
520 QList<AbstractInterface*> *intList = evalStringComplex(intName);
\r
521 int listSize = intList->count();
\r
522 res = "case " + sigName + " is\n";
\r
523 if(rxCaseUp->indexIn(cases)) {
\r
524 number = rxCaseUp->cap(1).toInt();
\r
525 for(int j = number; j < listSize; j++) {
\r
527 for(int i = 0; i < listSize; i++) {
\r
528 res += "\twhen " + QString::number(number) + " " + intList->at(i)->getName() + instruc + "\n";
\r
532 res += "\twhen " + number + ' ' + intName + instruc + "\n";
\r
536 if(rxCaseDown->indexIn(cases)) {
\r
537 number = rxCaseDown->cap(1).toInt();
\r
538 for(int j = number; j < listSize; j++) {
\r
540 for(int i = 0; i < listSize; i++) {
\r
541 res += "\twhen " + QString::number(number) + " " + intList->at(i)->getName() + instruc + "\n";
\r
545 res += "\twhen " + number + ' ' + intName + instruc + "\n";
\r
548 res += "end case ;\n";
\r
555 QString BlockImplementation::evalString(QString s) {
\r
557 QString name = getIfaceUserName(block->AbstractBlock::getIfaceFromName(s));
\r
561 QList<AbstractInterface*>* BlockImplementation::evalStringComplex(QString s) {
\r
564 QList<AbstractInterface*> *listInterfaces = new QList<AbstractInterface*>();
\r
565 AbstractInterface *inter = block->AbstractBlock::getIfaceFromName(s);
\r
566 QList<AbstractInterface*> listIntBlock = block->getInterfaces();
\r
567 for(int i = 0; i < listIntBlock.size(); i++) {
\r
568 if(inter->getName().compare(listIntBlock.at(i)->getName()) < -1) {
\r
569 listInterfaces->insert(j, inter);
\r
573 return listInterfaces;
\r
576 QString BlockImplementation::evalValue(QString s) {
\r
579 if(paramMap.contains(s))
\r
580 val = paramMap.value(s);
\r
584 QString BlockImplementation::getIfaceUserName(AbstractInterface* refIface) {
\r
586 if (! refIface->isReferenceInterface()) return "";
\r
588 AbstractInterface* funcIface = NULL;
\r
590 if (refIface->getDirection() == AbstractInterface::Input) {
\r
591 foreach(AbstractInterface* iface, block->getInputs()) {
\r
592 FunctionalInterface* fi = (FunctionalInterface*)iface;
\r
593 if (fi->getReference() == refIface) {
\r
599 else if (refIface->getDirection() == AbstractInterface::Output) {
\r
600 foreach(AbstractInterface* iface, block->getOutputs()) {
\r
601 FunctionalInterface* fi = (FunctionalInterface*)iface;
\r
602 if (fi->getReference() == refIface) {
\r
608 else if (refIface->getDirection() == AbstractInterface::InOut) {
\r
609 foreach(AbstractInterface* iface, block->getBidirs()) {
\r
610 FunctionalInterface* fi = (FunctionalInterface*)iface;
\r
611 if (fi->getReference() == refIface) {
\r
617 if (funcIface == NULL) return "";
\r
619 return funcIface->getName();
\r
622 QDataStream& operator<<(QDataStream &out, const BlockImplementation &impl) {
\r
624 out.setVersion(QDataStream::Qt_5_0);
\r
626 QByteArray blockData;
\r
627 QDataStream toWrite(&blockData, QIODevice::WriteOnly);
\r
629 toWrite << impl.xmlFile;
\r
630 toWrite << impl.referenceXml;
\r
631 toWrite << impl.referenceMd5;
\r
633 toWrite << impl.delta;
\r
634 toWrite << impl.consumptionPattern;
\r
635 toWrite << impl.productionPattern;
\r
636 toWrite << impl.productionCounter;
\r
643 QDataStream& operator>>(QDataStream &in, BlockImplementation &impl) {
\r
647 in.setVersion(QDataStream::Qt_5_0);
\r
651 in >> impl.xmlFile;
\r
652 in >> impl.referenceXml;
\r
653 in >> impl.referenceMd5;
\r
654 // loading patterns
\r
656 in >> impl.consumptionPattern;
\r
657 in >> impl.productionPattern;
\r
658 in >> impl.productionCounter;
\r
663 QString BlockImplementation::calculateWidth(QString s){
\r
664 QRegExp *rxWidth = new QRegExp("$*([a-zA-Z0-9_-]*)");
\r
665 QStringList matchList = s.split(" ");
\r
668 QList<BlockParameter*> listParams = reference->getParameters();
\r
670 while ((pos = rxWidth->indexIn(s, pos)) != -1) {
\r
671 matchList << rxWidth->cap(1);
\r
672 pos += rxWidth->matchedLength();
\r
675 for (int i = 0; i < matchList.size(); i++) {
\r
676 QString match = matchList.at(i);
\r
677 if(rxWidth->indexIn(match)) {
\r
678 for(int j = 0; j < listParams.size(); j++) {
\r
679 if(match.compare(listParams.at(j)->getName())) {
\r
680 BlockParameter *param = listParams.at(i);
\r
681 if(param->getContext() == "generic") {
\r
682 match = match.remove('$');
\r
685 match = param->getValue().toString();
\r
691 line = matchList.join(' ');
\r
692 evaluator->setExpression(line);
\r
693 res = evaluator->evaluate();
\r