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
10 BlockImplementation::BlockImplementation(const QString& _xmlFile) {
\r
11 xmlFile = _xmlFile;
\r
13 evaluator = new ArithmeticEvaluator;
\r
14 evaluator->setVariableMarkers("@$");
\r
17 BlockImplementation::BlockImplementation(const QString& _xmlFile, const QString &_referenceXml, const QString &_referenceMd5) {
\r
18 xmlFile = _xmlFile;
\r
19 referenceXml = _referenceXml;
\r
20 referenceMd5 = _referenceMd5;
\r
23 void BlockImplementation::assignPatterns(FunctionalBlock *_block) throw(Exception) {
\r
27 QFile implFile(xmlFile);
\r
29 // reading in into QDomDocument
\r
30 QDomDocument document("implFile");
\r
32 if (!implFile.open(QIODevice::ReadOnly)) {
\r
33 throw(Exception(IMPLFILE_NOACCESS));
\r
35 if (!document.setContent(&implFile)) {
\r
37 throw(Exception(IMPLFILE_NOACCESS));
\r
40 QDomElement impl = document.documentElement();
\r
41 QDomNodeList patternNode = impl.elementsByTagName("patterns");
\r
42 if (patternNode.isEmpty()) return;
\r
43 QDomElement patternElt = patternNode.at(0).toElement();
\r
47 void BlockImplementation::generateVHDL(FunctionalBlock* _block, const QString &path) throw(Exception) {
\r
51 QFile implFile(xmlFile);
\r
53 // reading in into QDomDocument
\r
54 QDomDocument document("implFile");
\r
56 if (!implFile.open(QIODevice::ReadOnly)) {
\r
57 throw(Exception(IMPLFILE_NOACCESS));
\r
59 if (!document.setContent(&implFile)) {
\r
61 throw(Exception(IMPLFILE_NOACCESS));
\r
65 bool genController = false;
\r
66 QString coreFile = "";
\r
67 QString controllerFile = "";
\r
69 if (reference->isWBConfigurable()) {
\r
70 genController = true;
\r
71 controllerFile = path;
\r
72 controllerFile.append(block->getName());
\r
73 controllerFile.append("_ctrl.vhd");
\r
76 controllerFile = "nofile.vhd";
\r
79 coreFile.append(block->getName());
\r
80 coreFile.append(".vhd");
\r
82 QFile vhdlCore(coreFile);
\r
83 QFile vhdlController(controllerFile);
\r
85 if (!vhdlCore.open(QIODevice::WriteOnly)) {
\r
86 throw(Exception(VHDLFILE_NOACCESS));
\r
89 if (genController) {
\r
90 if (!vhdlController.open(QIODevice::WriteOnly)) {
\r
91 throw(Exception(VHDLFILE_NOACCESS));
\r
94 QTextStream outCore(&vhdlCore);
\r
95 QTextStream outController;
\r
96 if (genController) {
\r
97 outController.setDevice(&vhdlController);
\r
103 //Get the root element
\r
104 QDomElement impl = document.documentElement();
\r
105 QDomElement eltComments = impl.firstChildElement("comments");
\r
106 generateComments(eltComments, coreFile, outCore);
\r
107 QDomElement eltLibs = eltComments.nextSiblingElement("libraries");
\r
108 generateLibraries(eltLibs, outCore);
\r
109 generateEntity(outCore, genController);
\r
110 QDomElement eltArch = eltLibs.nextSiblingElement("architecture");
\r
111 generateArchitecture(eltArch, outCore);
\r
112 if (genController) {
\r
113 generateController(outController);
\r
116 catch(Exception err) {
\r
121 vhdlController.close();
\r
124 // This function generates the comments part of the VHDL document
\r
125 void BlockImplementation::generateComments(QDomElement &elt, QString coreFile, QTextStream& out) throw(Exception) {
\r
127 for(int i = 0; i < 50; i++) {
\r
131 QString fileName = coreFile;
\r
132 out << "-- File : " << fileName << "\n";
\r
134 QDomElement eltAuthor = elt.firstChildElement("author");
\r
135 QString firstName = eltAuthor.attribute("firstname","");
\r
136 QString lastName = eltAuthor.attribute("lastname","");
\r
137 QString mail = eltAuthor.attribute("mail","");
\r
138 out << "-- Author(s) : "<<firstName+" "<<lastName<<" ("<<mail<<")\n";
\r
140 QDomElement eltDate = eltAuthor.nextSiblingElement("date");
\r
141 QString crea = eltDate.attribute("creation","");
\r
142 out << "-- Creation Date : "<<crea<<"\n";
\r
144 QDomElement eltRelated = eltDate.nextSiblingElement("related_files");
\r
145 QString relateds = eltRelated.attribute("list","");
\r
146 out << "-- Related files :\n"<<relateds<<"\n";
\r
148 QDomElement eltDesc = eltRelated.nextSiblingElement("description");
\r
149 QDomElement desc = eltDesc.firstChildElement();
\r
150 QString descTxt = desc.text();
\r
151 out << "-- Decription :\n"<<descTxt<<"\n";
\r
153 QDomElement eltNote = eltDesc.nextSiblingElement("description");
\r
154 QDomElement note = eltNote.firstChildElement();
\r
155 QString noteTxt = note.text();
\r
156 out << "-- Note :\n"<<noteTxt<<"\n";
\r
158 for(int i = 0; i < 50; i++) {
\r
164 // This function generates the library part of the VHDL document
\r
165 void BlockImplementation::generateLibraries(QDomElement &elt, QTextStream& out) throw(Exception) {
\r
167 QDomNodeList listLib = elt.elementsByTagName("library");
\r
168 for(int i = 0; i < listLib.length(); i++) {
\r
169 QDomNode nodeLib = listLib.item(i);
\r
170 QDomElement eltLib = nodeLib.toElement();
\r
171 QString nameLib = eltLib.attribute("name", "");
\r
172 out << "library " << nameLib << ";\n";
\r
173 QDomNodeList listPack = eltLib.elementsByTagName("package");
\r
174 for(int j = 0; j < listPack.length(); j++) {
\r
175 QDomNode nodePack = listPack.item(j);
\r
176 QDomElement eltPack = nodePack.toElement();
\r
177 QString namePack = eltPack.attribute("name", "");
\r
178 QString usePack = elt.attribute("use","");
\r
179 out << "use " << nameLib << "." << namePack << "." << usePack << ";\n";
\r
185 // This function generates the entity part of the VHDL document
\r
186 void BlockImplementation::generateEntity(QTextStream& out, bool hasController) throw(Exception) {
\r
189 nameEnt = reference->getName();
\r
190 //QList<BlockParameter*> listParams = reference->getParameters();
\r
191 QList<AbstractInterface*> listInputs = reference->getInputs();
\r
192 QList<AbstractInterface*> listOutputs = reference->getOutputs();
\r
193 QList<AbstractInterface*> listBidirs = reference->getBidirs();
\r
194 QString typePort, namePort;
\r
196 out << "entity " << nameEnt << " is\n";
\r
199 /* TODO : rewrite the generation to take into acocunt the new object hierarchy */
\r
201 // Generation of the generics
\r
202 QList<BlockParameter*> listGenerics = reference->getGenericParameters();
\r
203 if ((!listGenerics.isEmpty()) || (hasController)) {
\r
204 out << " generic (" << endl;
\r
205 if (hasController) {
\r
206 out << " wb_data_width : integer = 16;" << endl;
\r
207 out << " wb_addr_width : integer = 12";
\r
208 if (!listGenerics.isEmpty()) out << ";";
\r
211 for(i=0;i<listGenerics.size()-1;i++) {
\r
212 out << " " << listGenerics.at(i)->toVHDL(BlockParameter::Entity, 0);
\r
214 out << " " << listGenerics.at(i)->toVHDL(BlockParameter::Entity,BlockParameter::NoComma);
\r
216 out << " );" << endl;
\r
219 out << " port (" << endl;
\r
221 // Generation of the clk & rst signals
\r
222 out << " -- clk/rst" << endl;
\r
223 for(int i = 0; i < listInputs.size(); i++) {
\r
224 if(listInputs.at(i)->getPurpose() == AbstractInterface::Clock || listInputs.at(i)->getPurpose() == AbstractInterface::Reset) {
\r
225 out << " " << listInputs.at(i)->getName() << " : in std_logic;" << endl;
\r
229 if (hasController) {
\r
230 // Generation of the wishbone signals
\r
231 out << " -- registers r/w via wishbone" << endl;
\r
232 QList<BlockParameter*> listWB = reference->getWishboneParameters();
\r
233 for(i=0;i<listWB.size()-1;i++) {
\r
234 out << " " << listWB.at(i)->toVHDL(BlockParameter::Entity, 0);
\r
236 out << " " << listWB.at(i)->toVHDL(BlockParameter::Entity,BlockParameter::NoComma);
\r
240 // Generation of the data signals
\r
241 out << "-- data ports\n";
\r
242 for(int i = 0; i < listInputs.size(); i++) {
\r
243 namePort = getIfaceUserName(reference->AbstractBlock::getIfaceFromName(listInputs.at(i)->getName()));
\r
244 if(listInputs.at(i)->getWidth().compare("1"))
\r
245 typePort = "std_logic";
\r
247 typePort = calculateWidth(listInputs.at(i)->getWidth());
\r
248 if(listInputs.at(i)->getPurpose() == 1)
\r
249 out << namePort << " : in std_logic_vector(" << typePort << " -1 downto 0) ;\n";
\r
252 for(int i = 0; i < listOutputs.size(); i++) {
\r
253 namePort = getIfaceUserName(reference->AbstractBlock::getIfaceFromName(listOutputs.at(i)->getName()));
\r
254 if(listOutputs.at(i)->getWidth().compare("1"))
\r
255 typePort = "std_logic";
\r
257 typePort = calculateWidth(listOutputs.at(i)->getWidth());
\r
258 if(listOutputs.at(i)->getPurpose() == 1)
\r
259 out << namePort << " : out std_logic_vector(" << typePort << " -1 downto 0) ;\n";
\r
262 for(int i = 0; i < listBidirs.size(); i++) {
\r
263 namePort = getIfaceUserName(reference->AbstractBlock::getIfaceFromName(listBidirs.at(i)->getName()));
\r
264 if(listBidirs.at(i)->getWidth().compare(("1")))
\r
265 typePort = "std_logic";
\r
267 typePort = calculateWidth((listBidirs.at(i)->getWidth()));
\r
268 if(listBidirs.at(i)->getPurpose() == 1)
\r
269 out << namePort << " : inout std_logic_vector(" << typePort << " -1 downto 0) ;\n";
\r
273 // This function generates the architecture part of the VHDL document
\r
274 void BlockImplementation::generateArchitecture(QDomElement &elt, QTextStream& out) throw(Exception) {
\r
277 QDomElement eltArch = elt.nextSiblingElement("architecture");
\r
278 out << "architecture " << nameEnt <<"_1 of " << nameEnt << "is\n";
\r
279 QString implText = eltArch.text();
\r
280 QStringList listLine = implText.split("\n");
\r
281 for(int i =0; i < listLine.size(); i++) {
\r
282 if(listLine.at(i).contains(QRegularExpression("@foreach{")) != -1) {
\r
283 while(listLine.at(i).compare("@endforeach") != -1) {
\r
284 expr = expr + listLine.at(i) + '\n';
\r
287 expr = expr + listLine.at(i);
\r
288 out << evalComplex(expr, 1) << '\n';
\r
290 if(listLine.at(i).contains(QRegularExpression("@caseeach{")) != -1) {
\r
291 while(listLine.at(i).compare("@endcaseeach") != -1) {
\r
292 expr = expr + listLine.at(i) + '\n';
\r
295 expr = expr + listLine.at(i);
\r
296 out << evalComplex(expr, 2) << '\n';
\r
299 if(listLine.at(i).contains('@') == -1)
\r
300 out << listLine.at(i) << "\n";
\r
302 out << eval(listLine.at(i), out) << "\n";
\r
306 void BlockImplementation::generateController(QTextStream &out) throw(Exception) {
\r
309 QString BlockImplementation::eval(QString line, QTextStream& out) {
\r
310 QString res, s, begLine, endLine, expr;
\r
311 evaluator->setExpression(line);
\r
312 QRegExp *rxString = new QRegExp("(.*)@{(.*)}(.*)");
\r
313 QRegExp *rxValue = new QRegExp("(.*)@val{(.*)}(.*)");
\r
314 QRegExp *rxExpr = new QRegExp(".*@eval{(.*)}.*");
\r
316 int nbAt = line.count('@');
\r
318 for(int i = 0; i < line.size(); i++) {
\r
319 if(rxString->indexIn(line)) {
\r
320 begLine = rxString->cap(1);
\r
321 s = rxString->cap(2);
\r
322 endLine = rxString->cap(3);
\r
323 res = begLine + evalString(s) + endLine + '\n';
\r
327 for(int i = 0; i < line.size(); i++) {
\r
328 if(rxValue->indexIn(line)) {
\r
329 begLine = rxValue->cap(1);
\r
330 s = rxValue->cap(2);
\r
331 endLine = rxValue->cap(3);
\r
332 res = begLine + evalValue(s) + endLine + '\n';
\r
336 for(int i = 0; i < line.size(); i++) {
\r
337 if(rxExpr->indexIn(line)) {
\r
338 expr = rxExpr->cap(1);
\r
339 if(expr.count('@') == 0) {
\r
340 evaluator->setExpression(expr);
\r
341 s = QString::number(evaluator->evaluate());
\r
343 res = begLine + s + endLine + '\n';
\r
351 QString BlockImplementation::evalComplex(QString line, int id) {
\r
352 QString res, s, begLine, endLine, expr;
\r
353 QRegExp *rxString = new QRegExp("(.*)@{(.*)}(.*)");
\r
354 QRegExp *rxValue = new QRegExp("(.*)@val{(.*)}(.*)");
\r
355 QRegExp *rxExpr = new QRegExp(".*@eval{(.*)}.*");
\r
356 QRegExp *rxFor = new QRegExp("@foreach{.*}(@{.*})(.*)@endforeach");
\r
357 QRegExp *rxCase = new QRegExp("@caseeach{.*,(.*),(.*)}(@{.*})(.*)@endcaseeach");
\r
358 QRegExp *rxCaseDown = new QRegExp("@#-:(.*)");
\r
359 QRegExp *rxCaseUp = new QRegExp("@#:(.*)");
\r
360 evaluator->setExpression(line);
\r
362 int nbAt = line.count('@') - 2;
\r
364 for(int i = 0; i < line.size(); i++) {
\r
365 if(rxString->indexIn(line)) {
\r
366 begLine = rxString->cap(1);
\r
367 s = rxString->cap(2);
\r
368 endLine = rxString->cap(3);
\r
369 if(evalStringComplex(s)->size() == 0)
\r
370 line = begLine + evalString(s) + endLine;
\r
374 for(int i = 0; i < line.size(); i++) {
\r
375 if(rxValue->indexIn(line)) {
\r
376 begLine = rxValue->cap(1);
\r
377 s = rxValue->cap(2);
\r
378 endLine = rxValue->cap(3);
\r
379 line = begLine + evalValue(s) + endLine;
\r
383 for(int i = 0; i < line.size(); i++) {
\r
384 if(rxExpr->indexIn(line)) {
\r
385 expr = rxExpr->cap(1);
\r
386 if(expr.count('@') == 0) {
\r
387 evaluator->setExpression(expr);
\r
388 s = QString::number(evaluator->evaluate());
\r
390 res = begLine + s + endLine + '\n';
\r
397 if(rxFor->indexIn(line)) {
\r
398 QString intName, instruc;
\r
399 intName = rxFor->cap(1);
\r
400 instruc = rxFor->cap(2);
\r
401 QList<AbstractInterface*> *intList = evalStringComplex(intName);
\r
402 if(intList->size() != 0) {
\r
403 for(int i = 0; i < intList->size(); i++) {
\r
404 res = intList->at(i)->getName() + instruc + '\n';
\r
411 if(rxCase->indexIn(line)) {
\r
412 QString intName, sigName, cases, instruc;
\r
414 sigName = rxCase->cap(1);
\r
415 cases = rxCase->cap(2);
\r
416 intName = rxCase->cap(3);
\r
417 instruc = rxCase->cap(4);
\r
418 QList<AbstractInterface*> *intList = evalStringComplex(intName);
\r
419 int listSize = intList->count();
\r
420 res = "case " + sigName + " is\n";
\r
421 if(rxCaseUp->indexIn(cases)) {
\r
422 number = rxCaseUp->cap(1).toInt();
\r
423 for(int j = number; j < listSize; j++) {
\r
425 for(int i = 0; i < listSize; i++) {
\r
426 res += "\twhen " + QString::number(number) + " " + intList->at(i)->getName() + instruc + "\n";
\r
430 res += "\twhen " + number + ' ' + intName + instruc + "\n";
\r
434 if(rxCaseDown->indexIn(cases)) {
\r
435 number = rxCaseDown->cap(1).toInt();
\r
436 for(int j = number; j < listSize; j++) {
\r
438 for(int i = 0; i < listSize; i++) {
\r
439 res += "\twhen " + QString::number(number) + " " + intList->at(i)->getName() + instruc + "\n";
\r
443 res += "\twhen " + number + ' ' + intName + instruc + "\n";
\r
446 res += "end case ;\n";
\r
453 QString BlockImplementation::evalString(QString s) {
\r
455 QString name = getIfaceUserName(block->AbstractBlock::getIfaceFromName(s));
\r
459 QList<AbstractInterface*>* BlockImplementation::evalStringComplex(QString s) {
\r
462 QList<AbstractInterface*> *listInterfaces = new QList<AbstractInterface*>();
\r
463 AbstractInterface *inter = block->AbstractBlock::getIfaceFromName(s);
\r
464 QList<AbstractInterface*> listIntBlock = block->getInterfaces();
\r
465 for(int i = 0; i < listIntBlock.size(); i++) {
\r
466 if(inter->getName().compare(listIntBlock.at(i)->getName()) < -1) {
\r
467 listInterfaces->insert(j, inter);
\r
471 return listInterfaces;
\r
474 QString BlockImplementation::evalValue(QString s) {
\r
477 if(paramMap.contains(s))
\r
478 val = paramMap.value(s);
\r
482 QString BlockImplementation::getIfaceUserName(AbstractInterface* refIface) {
\r
484 if (! refIface->isReferenceInterface()) return "";
\r
486 AbstractInterface* funcIface = NULL;
\r
488 if (refIface->getDirection() == AbstractInterface::Input) {
\r
489 foreach(AbstractInterface* iface, block->getInputs()) {
\r
490 FunctionalInterface* fi = (FunctionalInterface*)iface;
\r
491 if (fi->getReference() == refIface) {
\r
497 else if (refIface->getDirection() == AbstractInterface::Output) {
\r
498 foreach(AbstractInterface* iface, block->getOutputs()) {
\r
499 FunctionalInterface* fi = (FunctionalInterface*)iface;
\r
500 if (fi->getReference() == refIface) {
\r
506 else if (refIface->getDirection() == AbstractInterface::InOut) {
\r
507 foreach(AbstractInterface* iface, block->getBidirs()) {
\r
508 FunctionalInterface* fi = (FunctionalInterface*)iface;
\r
509 if (fi->getReference() == refIface) {
\r
515 if (funcIface == NULL) return "";
\r
517 return funcIface->getName();
\r
520 QDataStream& operator<<(QDataStream &out, const BlockImplementation &impl) {
\r
522 out.setVersion(QDataStream::Qt_5_0);
\r
524 QByteArray blockData;
\r
525 QDataStream toWrite(&blockData, QIODevice::WriteOnly);
\r
527 toWrite << impl.xmlFile;
\r
528 toWrite << impl.referenceXml;
\r
529 toWrite << impl.referenceMd5;
\r
536 QDataStream& operator>>(QDataStream &in, BlockImplementation &impl) {
\r
540 in.setVersion(QDataStream::Qt_5_0);
\r
544 in >> impl.xmlFile;
\r
545 in >> impl.referenceXml;
\r
546 in >> impl.referenceMd5;
\r
551 QString BlockImplementation::calculateWidth(QString s){
\r
552 QRegExp *rxWidth = new QRegExp("$*([a-zA-Z0-9_-]*)");
\r
553 QStringList matchList = s.split(" ");
\r
556 QList<BlockParameter*> listParams = reference->getParameters();
\r
558 while ((pos = rxWidth->indexIn(s, pos)) != -1) {
\r
559 matchList << rxWidth->cap(1);
\r
560 pos += rxWidth->matchedLength();
\r
563 for (int i = 0; i < matchList.size(); i++) {
\r
564 QString match = matchList.at(i);
\r
565 if(rxWidth->indexIn(match)) {
\r
566 for(int j = 0; j < listParams.size(); j++) {
\r
567 if(match.compare(listParams.at(j)->getName())) {
\r
568 BlockParameter *param = listParams.at(i);
\r
569 if(param->getContext() == "generic") {
\r
570 match = match.remove('$');
\r
573 match = param->getValue().toString();
\r
579 line = matchList.join(' ');
\r
580 evaluator->setExpression(line);
\r
581 res = evaluator->evaluate();
\r