Qucs-GUI  0.0.19
/home/travis/build/Qucs/qucs/qucs/qucs/components/vhdlfile.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                                vhdlfile.cpp
00003                               --------------
00004     begin                : Sat Apr 15 2006
00005     copyright            : (C) 2006 by Michael Margraf
00006     email                : michael.margraf@alumni.tu-berlin.de
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 #include "vhdlfile.h"
00018 #include "qucs.h"
00019 #include "main.h"
00020 #include "schematic.h"
00021 #include "misc.h"
00022 
00023 #include <QTextStream>
00024 #include <QRegExp>
00025 #include <QFileInfo>
00026 
00027 
00028 VHDL_File::VHDL_File()
00029 {
00030   Type = isDigitalComponent;
00031   Description = QObject::tr("VHDL file");
00032 
00033   Props.append(new Property("File", "sub.vhdl", false,
00034     QObject::tr("Name of VHDL file")));
00035 
00036   Model = "VHDL";
00037   Name  = "X";
00038 
00039   // Do NOT call createSymbol() here. But create port to let it rotate.
00040   Ports.append(new Port(0, 0));
00041 }
00042 
00043 // -------------------------------------------------------
00044 Component* VHDL_File::newOne()
00045 {
00046   VHDL_File *p = new VHDL_File();
00047   p->Props.getFirst()->Value = Props.getFirst()->Value;
00048   p->recreate(0);
00049   return p;
00050 }
00051 
00052 // -------------------------------------------------------
00053 Element* VHDL_File::info(QString& Name, char* &BitmapFile, bool getNewOne)
00054 {
00055   Name = QObject::tr("VHDL file");
00056   BitmapFile = (char *) "vhdlfile";
00057 
00058   if(getNewOne) {
00059     VHDL_File *p = new VHDL_File();
00060     p->recreate(0);   // createSymbol() is NOT called in constructor !!!
00061     return p;
00062   }
00063   return 0;
00064 }
00065 
00066 // -------------------------------------------------------
00067 QString VHDL_File::vhdlCode(int)
00068 {
00069   QString s;
00070   QListIterator<Port *> iport(Ports);
00071   Port *pp = iport.next();
00072   if(pp) {
00073     s = "  " + Name + ": entity " + EntityName;
00074 
00075     // output all generic properties
00076     Property *pr = Props.at(1);
00077     if (pr) {
00078       s += " generic map (";
00079       s += pr->Value;
00080       for(pr = Props.next(); pr != 0; pr = Props.next())
00081   s += ", " + pr->Value;
00082       s += ")";
00083     }
00084 
00085     // output all node names
00086     s += " port map (";
00087     if(pp)  s += pp->Connection->Name;
00088     while (iport.hasNext()) {
00089       pp = iport.next();
00090       s += ", "+pp->Connection->Name;   // node names
00091     }
00092     s += ");\n";
00093   }
00094   return s;
00095 }
00096 
00097 // -------------------------------------------------------
00098 // Returns a comma separated list of the port names of the last
00099 // entity in this file.
00100 QString VHDL_File::loadFile()
00101 {
00102   QString File(Props.getFirst()->Value);
00103   QFileInfo Info(File);
00104   if(Info.isRelative())
00105     File = QucsSettings.QucsWorkDir.filePath(File);
00106 
00107   QFile f(File);
00108   if(!f.open(QIODevice::ReadOnly))
00109     return QString("");
00110 
00111   QTextStream stream(&f);
00112   File = stream.readAll();   // QString is better for "find" function
00113   f.close();
00114 
00115   // parse ports, i.e. network connections; and generics, i.e. parameters
00116   VHDL_File_Info VInfo(File);
00117   GenNames = VInfo.GenNames;
00118   EntityName = VInfo.EntityName;
00119   TypeNames = VInfo.TypeNames;
00120   GenTypes = VInfo.GenTypes;
00121   GenDefs = VInfo.GenDefs;
00122   return VInfo.PortNames;
00123 }
00124 
00125 // -------------------------------------------------------
00126 void VHDL_File::createSymbol()
00127 {
00128   // use the screen-compatible metric
00129   QFontMetrics  metrics(QucsSettings.font, 0);   // get size of text
00130   int fHeight = metrics.lineSpacing();
00131 
00132   int No = 0;
00133   TypeNames = "";
00134   QString tmp, PortNames = loadFile();
00135   if(!PortNames.isEmpty())
00136     No = PortNames.count(',') + 1;
00137 
00138   #define HALFWIDTH  17
00139   int h = 30*((No-1)/2) + 15;
00140   Lines.append(new Line(-HALFWIDTH, -h, HALFWIDTH, -h,QPen(Qt::darkBlue,2)));
00141   Lines.append(new Line( HALFWIDTH, -h, HALFWIDTH,  h,QPen(Qt::darkBlue,2)));
00142   Lines.append(new Line(-HALFWIDTH,  h, HALFWIDTH,  h,QPen(Qt::darkBlue,2)));
00143   Lines.append(new Line(-HALFWIDTH, -h,-HALFWIDTH,  h,QPen(Qt::darkBlue,2)));
00144 
00145   tmp = QObject::tr("vhdl");
00146   int w = metrics.width(tmp);
00147   Texts.append(new Text(w/-2, fHeight/-2, tmp));
00148 
00149   int y = 15-h, i = 0;
00150   Port *pp;
00151   while(i<No) {
00152     Lines.append(new Line(-30,  y,-HALFWIDTH,  y,QPen(Qt::darkBlue,2)));
00153     pp = new Port(-30,  y);
00154     Ports.append(pp);
00155     pp->Type = TypeNames.section(',', i, i);
00156     tmp = PortNames.section(',', i, i);
00157     w = metrics.width(tmp);
00158     Texts.append(new Text(-19-w, y-fHeight-2, tmp));
00159     i++;
00160 
00161     if(i == No) break;
00162     Lines.append(new Line(HALFWIDTH,  y, 30,  y,QPen(Qt::darkBlue,2)));
00163     pp = new Port( 30,  y);
00164     Ports.append(pp);
00165     pp->Type = TypeNames.section(',', i, i);
00166     tmp = PortNames.section(',', i, i);
00167     Texts.append(new Text( 20, y-fHeight-2, tmp));
00168     y += 60;
00169     i++;
00170   }
00171 
00172   x1 = -30; y1 = -h-2;
00173   x2 =  30; y2 =  h+2;
00174   tx = x1+4;
00175   ty = y2+4;
00176 
00177   // now create/modify properties
00178   No = 0;
00179   if(!GenNames.isEmpty())
00180     No = (GenNames.count(',')) + 1;
00181   Property * pr = Props.at(1);
00182   for(i=0; i<No; i++) {
00183     if (!pr) {
00184       pr = new Property(GenNames.section(',', i, i),
00185       GenDefs.section(',', i, i), true,
00186       QObject::tr("generic variable")+
00187       " "+QString::number(i+1));
00188       Props.append(pr);
00189       pr = 0;
00190     }
00191     else {
00192       pr->Description =
00193   QObject::tr("generic variable")+" "+QString::number(i+1);
00194       pr->Name = GenNames.section(',', i, i);
00195       pr = Props.next();
00196     }
00197   }
00198   // remove remaining properties if necessary
00199   y=Props.count()-1;
00200   for(i=No; i<y; i++) {
00201     Props.removeLast();
00202   }
00203 }
00204 
00205 // -------------------------------------------------------
00206 QString VHDL_File::getSubcircuitFile()
00207 {
00208   // construct full filename
00209   QString FileName = Props.getFirst()->Value;
00210   return misc::properAbsFileName(FileName);
00211 }
00212 
00213 // -------------------------------------------------------
00214 bool VHDL_File::createSubNetlist(QTextStream *stream)
00215 {
00216   ErrText = "";
00217 
00218   // check filename
00219   QString FileName = Props.getFirst()->Value;
00220   if(FileName.isEmpty()) {
00221     ErrText += QObject::tr("ERROR: No file name in %1 component \"%2\".").
00222       arg(Model).arg(Name);
00223     return false;
00224   }
00225 
00226   // construct full filename
00227   FileName = getSubcircuitFile();
00228 
00229   // open file for reading
00230   QFile f(FileName);
00231   if(!f.open(QIODevice::ReadOnly)) {
00232     ErrText += QObject::tr("ERROR: Cannot open %1 file \"%2\".").
00233       arg(Model).arg(FileName);
00234     return false;
00235   }
00236 
00237   // write the whole VHDL file into the netlist output
00238   QByteArray FileContent = f.readAll();
00239   f.close();
00240   (*stream) << '\n';
00241   //? stream->writeRawBytes(FileContent.data(), FileContent.size());
00242   (*stream) << FileContent.data();
00243   (*stream) << '\n';
00244   return true;
00245 }
00246 
00247 // -------------------------------------------------------
00248 VHDL_File_Info::VHDL_File_Info()
00249 {
00250   EntityName = "";
00251   PortNames = "";
00252   TypeNames = "";
00253   GenTypes = "";
00254   GenNames = "";
00255   GenDefs = "";
00256 }
00257 
00258 // -------------------------------------------------------
00259 VHDL_File_Info::VHDL_File_Info(QString File, bool isfile)
00260 {
00261   if (isfile) {
00262     QFile f(File);
00263     if(!f.open(QIODevice::ReadOnly))
00264       File = "";
00265     else {
00266       QByteArray FileContent = f.readAll();
00267       File = QString(FileContent);
00268     }
00269     f.close();
00270   }
00271   
00272   QString s;
00273   PortNames = "";
00274   int i=0, j, k=0;
00275   while((i=File.indexOf("--", i)) >= 0) { // remove all VHDL comments
00276     j = File.indexOf('\n', i+2);          // This also finds "--" within a ...
00277     if(j < 0)                          // string, but as no strings are ...
00278       File = File.left(i);             // allowed in entity headers, it ...
00279     else                               // does not matter.
00280       File.remove(i, j-i);
00281   }
00282 
00283   QRegExp Expr;
00284   Expr.setCaseSensitivity(Qt::CaseInsensitive); 
00285   for(;;) {
00286     k--;
00287     Expr.setPattern("\\bentity\\b");  // start of last entity
00288     k = File.lastIndexOf(Expr, k);
00289     if(k < 0)
00290       return;
00291 
00292     Expr.setPattern("\\bend\\b");    // end of last entity
00293     i = File.indexOf(Expr, k+7);
00294     if(i < 0)
00295       return;
00296     s = File.mid(k+7, i-k-7);  // cut out entity declaration
00297 
00298     Expr.setPattern("\\b");
00299     i = s.indexOf(Expr);
00300     if(i < 0)
00301       return;
00302     j = s.indexOf(Expr, i+1);
00303     if(j < 0)
00304       return;
00305     EntityName = s.mid(i, j-i);  // save entity name
00306 
00307     i = s.indexOf(Expr, j+1);
00308     if(i < 0)
00309       return;
00310     j = s.indexOf(Expr, i+1);
00311     if(j < 0)
00312       return;
00313     if(s.mid(i, j-i).toLower() == "is")   // really found start of entity ?
00314       break;
00315 
00316     if(k < 1)    // already searched the whole text
00317       return;
00318   }
00319 
00320   // parse ports, i.e. network connections; and generics, i.e. parameters
00321   GenNames = parseGenerics(s,j);
00322   PortNames = parsePorts(s,j);
00323 }
00324 
00325 // -------------------------------------------------------
00326 QString VHDL_File_Info::parsePorts(QString s, int j)
00327 {
00328   QRegExp Expr;
00329   Expr.setCaseSensitivity(Qt::CaseInsensitive);
00330   int i, p, l, k;
00331 
00332   Expr.setPattern("\\bport\\b");  // start of interface definition
00333   i = s.indexOf(Expr, j+1);
00334   if(i < 0)
00335     return QString("");
00336   // find opening (
00337   i = s.indexOf('(', i+4) + 1;
00338   if(i <= 0)
00339     return QString("");
00340 
00341   // find closing (
00342   p = i;
00343   j = i-1;
00344   do {
00345     j = s.indexOf(')', j+1);
00346     if(j < 0)
00347       return QString("");
00348     p = s.indexOf('(', p+1);
00349     if(p >= 0 && p > j) p = -1;
00350   } while (p >= 0);
00351 
00352   s = s.mid(i, j-i);
00353   s.remove('\n');
00354   s.remove('\t');
00355 
00356   // find port names and types in parameter specification
00357   l = i = 0;    // remove all VHDL identifiers (e.g. ": out bit;")
00358   QString types = "", t;
00359   while((i=s.indexOf(':', i)) >= 0) {
00360     j = s.indexOf(';', i+2);
00361     if(j < 0) {
00362       t = s.mid(i+1);
00363       t.remove(';');
00364       t = t.simplified();
00365       s = s.left(i);
00366     } else {
00367       t = s.mid(i+1, j-i);
00368       t.remove(';');
00369       t = t.simplified();
00370       s.remove(i, j-i);
00371     }
00372     if ((k = t.indexOf(' ')) >= 0)
00373       t = t.mid(k+1);
00374     t = t.simplified();
00375     k = s.indexOf(';',l+2);
00376     k = (s.mid(l,k-l).count(',')) + 1;
00377     while (k-->0) types = types + t + ",";
00378     i--;
00379     l = i;
00380   }
00381 
00382   s.remove(' ');
00383   s.replace(';', ',');
00384   TypeNames=types=types.left(types.length()-1);
00385   return s;
00386 }
00387 
00388 // -------------------------------------------------------
00389 QString VHDL_File_Info::parseGenerics(QString s, int j)
00390 {
00391   QRegExp Expr;
00392   Expr.setCaseSensitivity(Qt::CaseInsensitive);
00393   int i, p, l, k, n;
00394 
00395   Expr.setPattern("\\bgeneric\\b");
00396   i = s.indexOf(Expr, j+1);
00397   if(i < 0)
00398     return QString("");
00399   // find opening (
00400   i = s.indexOf('(', i+4) + 1;
00401   if(i <= 0)
00402     return QString("");
00403 
00404   // find closing (
00405   p = i;
00406   j = i-1;
00407   do {
00408     j = s.indexOf(')', j+1);
00409     if(j < 0)
00410       return QString("");
00411     p = s.indexOf('(', p+1);
00412     if(p >= 0 && p > j) p = -1;
00413   } while (p >= 0);
00414 
00415   s = s.mid(i, j-i);
00416   s.remove('\n');
00417   s.remove('\t');
00418 
00419   // find generic names, types and defaults in parameter specification
00420   l = i = 0;
00421   QString types = "", t, defs = "", d;
00422   while((i=s.indexOf(':', i)) >= 0) {
00423     j = s.indexOf(';', i+2);
00424     n = s.indexOf(":=", i+2);
00425     d = "";
00426     if(n >= 0 && (n < j || j < 0) ) {
00427       j = s.indexOf(';', n+2);
00428       if(j < 0) {
00429   d = s.mid(n+2);
00430   d = d.simplified();
00431   s = s.left(n);
00432       } else {
00433   d = s.mid(n+2, j-n-1);
00434   d.remove(';');
00435   d = d.simplified();
00436   s.remove(n, j-n);
00437       }
00438       j = s.indexOf(';', n);
00439     }
00440     if(j < 0) {
00441       t = s.mid(i+1);
00442       t.remove(';');
00443       t = t.simplified();
00444       s = s.left(i);
00445     } else {
00446       t = s.mid(i+1, j-i);
00447       t.remove(';');
00448       t = t.simplified();
00449       s.remove(i, j-i);
00450     }
00451     if ((k = t.indexOf(' ')) >= 0)
00452       t = t.mid(k+1);
00453     t = t.simplified();
00454     k = s.indexOf(';',l+2);
00455     k = (s.mid(l,k-l).count(',')) + 1;
00456     while (k-->0) {
00457       types = types + t + ",";
00458       defs = defs + d + ",";
00459     }
00460     i--;
00461     l = i;
00462   }
00463 
00464   s.remove(' ');
00465   s.replace(';', ',');
00466   GenTypes=types=types.left(types.length()-1);
00467   GenDefs=defs=defs.left(defs.length()-1);
00468   return s;
00469 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines