Qucs-GUI
0.0.19
|
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 }