Qucs-GUI
0.0.19
|
00001 /*************************************************************************** 00002 schematic_file.cpp 00003 -------------------- 00004 begin : Sat Mar 27 2004 00005 copyright : (C) 2003 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 00018 #ifdef HAVE_CONFIG_H 00019 # include <config.h> 00020 #endif 00021 00022 #include <QtCore> 00023 #include <QMessageBox> 00024 #include <QDir> 00025 #include <QStringList> 00026 #include <QPlainTextEdit> 00027 #include <Q3PtrList> 00028 #include <QTextStream> 00029 #include <QList> 00030 #include <QProcess> 00031 #include <QDebug> 00032 00033 #include "main.h" 00034 #include "node.h" 00035 #include "schematic.h" 00036 #include "diagrams/diagrams.h" 00037 #include "paintings/paintings.h" 00038 #include "components/spicefile.h" 00039 #include "components/vhdlfile.h" 00040 #include "components/verilogfile.h" 00041 #include "components/libcomp.h" 00042 #include "module.h" 00043 #include "misc.h" 00044 00045 00046 // Here the subcircuits, SPICE components etc are collected. It must be 00047 // global to also work within the subcircuits. 00048 SubMap FileList; 00049 00050 00051 // ------------------------------------------------------------- 00052 // Creates a Qucs file format (without document properties) in the returning 00053 // string. This is used to copy the selected elements into the clipboard. 00054 QString Schematic::createClipboardFile() 00055 { 00056 int z=0; // counts selected elements 00057 Wire *pw; 00058 Diagram *pd; 00059 Painting *pp; 00060 Component *pc; 00061 00062 QString s("<Qucs Schematic " PACKAGE_VERSION ">\n"); 00063 00064 // Build element document. 00065 s += "<Components>\n"; 00066 for(pc = Components->first(); pc != 0; pc = Components->next()) 00067 if(pc->isSelected) { 00068 s += pc->save()+"\n"; z++; } 00069 s += "</Components>\n"; 00070 00071 s += "<Wires>\n"; 00072 for(pw = Wires->first(); pw != 0; pw = Wires->next()) 00073 if(pw->isSelected) { 00074 z++; 00075 if(pw->Label) if(!pw->Label->isSelected) { 00076 s += pw->save().section('"', 0, 0)+"\"\" 0 0 0>\n"; 00077 continue; 00078 } 00079 s += pw->save()+"\n"; 00080 } 00081 for(Node *pn = Nodes->first(); pn != 0; pn = Nodes->next()) 00082 if(pn->Label) if(pn->Label->isSelected) { 00083 s += pn->Label->save()+"\n"; z++; } 00084 s += "</Wires>\n"; 00085 00086 s += "<Diagrams>\n"; 00087 for(pd = Diagrams->first(); pd != 0; pd = Diagrams->next()) 00088 if(pd->isSelected) { 00089 s += pd->save()+"\n"; z++; } 00090 s += "</Diagrams>\n"; 00091 00092 s += "<Paintings>\n"; 00093 for(pp = Paintings->first(); pp != 0; pp = Paintings->next()) 00094 if(pp->isSelected) 00095 if(pp->Name.at(0) != '.') { // subcircuit specific -> do not copy 00096 s += "<"+pp->save()+">\n"; z++; } 00097 s += "</Paintings>\n"; 00098 00099 if(z == 0) return ""; // return empty if no selection 00100 00101 return s; 00102 } 00103 00104 // ------------------------------------------------------------- 00105 // Only read fields without loading them. 00106 bool Schematic::loadIntoNothing(QTextStream *stream) 00107 { 00108 QString Line, cstr; 00109 while(!stream->atEnd()) { 00110 Line = stream->readLine(); 00111 if(Line.at(0) == '<') if(Line.at(1) == '/') return true; 00112 } 00113 00114 QMessageBox::critical(0, QObject::tr("Error"), 00115 QObject::tr("Format Error:\n'Painting' field is not closed!")); 00116 return false; 00117 } 00118 00119 // ------------------------------------------------------------- 00120 // Paste from clipboard. 00121 bool Schematic::pasteFromClipboard(QTextStream *stream, Q3PtrList<Element> *pe) 00122 { 00123 QString Line; 00124 00125 Line = stream->readLine(); 00126 if(Line.left(16) != "<Qucs Schematic ") // wrong file type ? 00127 return false; 00128 00129 QString s = PACKAGE_VERSION; 00130 Line = Line.mid(16, Line.length()-17); 00131 if(Line != s) { // wrong version number ? 00132 QMessageBox::critical(0, QObject::tr("Error"), 00133 QObject::tr("Wrong document version: ")+Line); 00134 return false; 00135 } 00136 00137 // read content in symbol edit mode ************************* 00138 if(symbolMode) { 00139 while(!stream->atEnd()) { 00140 Line = stream->readLine(); 00141 if(Line == "<Components>") { 00142 if(!loadIntoNothing(stream)) return false; } 00143 else 00144 if(Line == "<Wires>") { 00145 if(!loadIntoNothing(stream)) return false; } 00146 else 00147 if(Line == "<Diagrams>") { 00148 if(!loadIntoNothing(stream)) return false; } 00149 else 00150 if(Line == "<Paintings>") { 00151 if(!loadPaintings(stream, (Q3PtrList<Painting>*)pe)) return false; } 00152 else { 00153 QMessageBox::critical(0, QObject::tr("Error"), 00154 QObject::tr("Clipboard Format Error:\nUnknown field!")); 00155 return false; 00156 } 00157 } 00158 00159 return true; 00160 } 00161 00162 // read content in schematic edit mode ************************* 00163 while(!stream->atEnd()) { 00164 Line = stream->readLine(); 00165 if(Line == "<Components>") { 00166 if(!loadComponents(stream, (Q3PtrList<Component>*)pe)) return false; } 00167 else 00168 if(Line == "<Wires>") { 00169 if(!loadWires(stream, pe)) return false; } 00170 else 00171 if(Line == "<Diagrams>") { 00172 if(!loadDiagrams(stream, (Q3PtrList<Diagram>*)pe)) return false; } 00173 else 00174 if(Line == "<Paintings>") { 00175 if(!loadPaintings(stream, (Q3PtrList<Painting>*)pe)) return false; } 00176 else { 00177 QMessageBox::critical(0, QObject::tr("Error"), 00178 QObject::tr("Clipboard Format Error:\nUnknown field!")); 00179 return false; 00180 } 00181 } 00182 00183 return true; 00184 } 00185 00186 // ------------------------------------------------------------- 00187 int Schematic::saveSymbolCpp (void) 00188 { 00189 QFileInfo info (DocName); 00190 QString cppfile = info.dirPath () + QDir::separator() + DataSet; 00191 QFile file (cppfile); 00192 00193 if (!file.open (QIODevice::WriteOnly)) { 00194 QMessageBox::critical (0, QObject::tr("Error"), 00195 QObject::tr("Cannot save C++ file \"%1\"!").arg(cppfile)); 00196 return -1; 00197 } 00198 00199 QTextStream stream (&file); 00200 00201 // automatically compute boundings of drawing 00202 int xmin = INT_MAX; 00203 int ymin = INT_MAX; 00204 int xmax = INT_MIN; 00205 int ymax = INT_MIN; 00206 int x1, y1, x2, y2; 00207 int maxNum = 0; 00208 Painting * pp; 00209 00210 stream << " // symbol drawing code\n"; 00211 for (pp = SymbolPaints.first (); pp != 0; pp = SymbolPaints.next ()) { 00212 if (pp->Name == ".ID ") continue; 00213 if (pp->Name == ".PortSym ") { 00214 if (((PortSymbol*)pp)->numberStr.toInt() > maxNum) 00215 maxNum = ((PortSymbol*)pp)->numberStr.toInt(); 00216 x1 = ((PortSymbol*)pp)->cx; 00217 y1 = ((PortSymbol*)pp)->cy; 00218 if (x1 < xmin) xmin = x1; 00219 if (x1 > xmax) xmax = x1; 00220 if (y1 < ymin) ymin = y1; 00221 if (y1 > ymax) ymax = y1; 00222 continue; 00223 } 00224 pp->Bounding (x1, y1, x2, y2); 00225 if (x1 < xmin) xmin = x1; 00226 if (x2 > xmax) xmax = x2; 00227 if (y1 < ymin) ymin = y1; 00228 if (y2 > ymax) ymax = y2; 00229 stream << " " << pp->saveCpp () << "\n"; 00230 } 00231 00232 stream << "\n // terminal definitions\n"; 00233 for (int i = 1; i <= maxNum; i++) { 00234 for (pp = SymbolPaints.first (); pp != 0; pp = SymbolPaints.next ()) { 00235 if (pp->Name == ".PortSym ") 00236 if (((PortSymbol*)pp)->numberStr.toInt() == i) 00237 stream << " " << pp->saveCpp () << "\n"; 00238 } 00239 } 00240 00241 stream << "\n // symbol boundings\n" 00242 << " x1 = " << xmin << "; " << " y1 = " << ymin << ";\n" 00243 << " x2 = " << xmax << "; " << " y2 = " << ymax << ";\n"; 00244 00245 stream << "\n // property text position\n"; 00246 for (pp = SymbolPaints.first (); pp != 0; pp = SymbolPaints.next ()) 00247 if (pp->Name == ".ID ") 00248 stream << " " << pp->saveCpp () << "\n"; 00249 00250 file.close (); 00251 return 0; 00252 } 00253 00254 // save symbol paintings in JSON format 00255 int Schematic::saveSymbolJSON() 00256 { 00257 QFileInfo info (DocName); 00258 QString jsonfile = info.dirPath () + QDir::separator() 00259 + info.baseName() + "_sym.json"; 00260 00261 qDebug() << "saveSymbolJson for " << jsonfile; 00262 00263 QFile file (jsonfile); 00264 00265 if (!file.open (QIODevice::WriteOnly)) { 00266 QMessageBox::critical (0, QObject::tr("Error"), 00267 QObject::tr("Cannot save JSON symbol file \"%1\"!").arg(jsonfile)); 00268 return -1; 00269 } 00270 00271 QTextStream stream (&file); 00272 00273 // automatically compute boundings of drawing 00274 int xmin = INT_MAX; 00275 int ymin = INT_MAX; 00276 int xmax = INT_MIN; 00277 int ymax = INT_MIN; 00278 int x1, y1, x2, y2; 00279 int maxNum = 0; 00280 Painting * pp; 00281 00282 stream << "{\n"; 00283 00284 stream << "\"paintings\" : [\n"; 00285 00286 // symbol drawing code" 00287 for (pp = SymbolPaints.first (); pp != 0; pp = SymbolPaints.next ()) { 00288 if (pp->Name == ".ID ") continue; 00289 if (pp->Name == ".PortSym ") { 00290 if (((PortSymbol*)pp)->numberStr.toInt() > maxNum) 00291 maxNum = ((PortSymbol*)pp)->numberStr.toInt(); 00292 x1 = ((PortSymbol*)pp)->cx; 00293 y1 = ((PortSymbol*)pp)->cy; 00294 if (x1 < xmin) xmin = x1; 00295 if (x1 > xmax) xmax = x1; 00296 if (y1 < ymin) ymin = y1; 00297 if (y1 > ymax) ymax = y1; 00298 continue; 00299 } 00300 pp->Bounding (x1, y1, x2, y2); 00301 if (x1 < xmin) xmin = x1; 00302 if (x2 > xmax) xmax = x2; 00303 if (y1 < ymin) ymin = y1; 00304 if (y2 > ymax) ymax = y2; 00305 stream << " " << pp->saveJSON() << "\n"; 00306 } 00307 00308 // terminal definitions 00309 //stream << "terminal \n"; 00310 for (int i = 1; i <= maxNum; i++) { 00311 for (pp = SymbolPaints.first (); pp != 0; pp = SymbolPaints.next ()) { 00312 if (pp->Name == ".PortSym ") 00313 if (((PortSymbol*)pp)->numberStr.toInt() == i) 00314 stream << " " << pp->saveJSON () << "\n"; 00315 } 00316 } 00317 00318 stream << "],\n"; //end of paintings JSON array 00319 00320 // symbol boundings 00321 stream 00322 << " \"x1\" : " << xmin << ",\n" << " \"y1\" : " << ymin << ",\n" 00323 << " \"x2\" : " << xmax << ",\n" << " \"y2\" : " << ymax << ",\n"; 00324 00325 // property text position 00326 for (pp = SymbolPaints.first (); pp != 0; pp = SymbolPaints.next ()) 00327 if (pp->Name == ".ID ") 00328 stream << " " << pp->saveJSON () << "\n"; 00329 00330 stream << "}\n"; 00331 00332 file.close (); 00333 return 0; 00334 00335 00336 } 00337 00338 // ------------------------------------------------------------- 00339 // Returns the number of subcircuit ports. 00340 int Schematic::saveDocument() 00341 { 00342 QFile file(DocName); 00343 if(!file.open(QIODevice::WriteOnly)) { 00344 QMessageBox::critical(0, QObject::tr("Error"), 00345 QObject::tr("Cannot save document!")); 00346 return -1; 00347 } 00348 00349 QTextStream stream(&file); 00350 00351 stream << "<Qucs Schematic " << PACKAGE_VERSION << ">\n"; 00352 00353 stream << "<Properties>\n"; 00354 if(symbolMode) { 00355 stream << " <View=" << tmpViewX1<<","<<tmpViewY1<<"," 00356 << tmpViewX2<<","<<tmpViewY2<< ","; 00357 stream <<tmpScale<<","<<tmpPosX<<","<<tmpPosY << ">\n"; 00358 } 00359 else { 00360 stream << " <View=" << ViewX1<<","<<ViewY1<<"," 00361 << ViewX2<<","<<ViewY2<< ","; 00362 stream << Scale <<","<<contentsX()<<","<<contentsY() << ">\n"; 00363 } 00364 stream << " <Grid=" << GridX<<","<<GridY<<"," 00365 << GridOn << ">\n"; 00366 stream << " <DataSet=" << DataSet << ">\n"; 00367 stream << " <DataDisplay=" << DataDisplay << ">\n"; 00368 stream << " <OpenDisplay=" << SimOpenDpl << ">\n"; 00369 stream << " <Script=" << Script << ">\n"; 00370 stream << " <RunScript=" << SimRunScript << ">\n"; 00371 stream << " <showFrame=" << showFrame << ">\n"; 00372 00373 QString t; 00374 misc::convert2ASCII(t = Frame_Text0); 00375 stream << " <FrameText0=" << t << ">\n"; 00376 misc::convert2ASCII(t = Frame_Text1); 00377 stream << " <FrameText1=" << t << ">\n"; 00378 misc::convert2ASCII(t = Frame_Text2); 00379 stream << " <FrameText2=" << t << ">\n"; 00380 misc::convert2ASCII(t = Frame_Text3); 00381 stream << " <FrameText3=" << t << ">\n"; 00382 stream << "</Properties>\n"; 00383 00384 Painting *pp; 00385 stream << "<Symbol>\n"; // save all paintings for symbol 00386 for(pp = SymbolPaints.first(); pp != 0; pp = SymbolPaints.next()) 00387 stream << " <" << pp->save() << ">\n"; 00388 stream << "</Symbol>\n"; 00389 00390 stream << "<Components>\n"; // save all components 00391 for(Component *pc = DocComps.first(); pc != 0; pc = DocComps.next()) 00392 stream << " " << pc->save() << "\n"; 00393 stream << "</Components>\n"; 00394 00395 stream << "<Wires>\n"; // save all wires 00396 for(Wire *pw = DocWires.first(); pw != 0; pw = DocWires.next()) 00397 stream << " " << pw->save() << "\n"; 00398 00399 // save all labeled nodes as wires 00400 for(Node *pn = DocNodes.first(); pn != 0; pn = DocNodes.next()) 00401 if(pn->Label) stream << " " << pn->Label->save() << "\n"; 00402 stream << "</Wires>\n"; 00403 00404 stream << "<Diagrams>\n"; // save all diagrams 00405 for(Diagram *pd = DocDiags.first(); pd != 0; pd = DocDiags.next()) 00406 stream << " " << pd->save() << "\n"; 00407 stream << "</Diagrams>\n"; 00408 00409 stream << "<Paintings>\n"; // save all paintings 00410 for(pp = DocPaints.first(); pp != 0; pp = DocPaints.next()) 00411 stream << " <" << pp->save() << ">\n"; 00412 stream << "</Paintings>\n"; 00413 00414 file.close(); 00415 00416 // additionally save symbol C++ code if in a symbol drawing and the 00417 // associated file is a Verilog-A file 00418 if (fileSuffix () == "sym") { 00419 if (fileSuffix (DataDisplay) == "va") { 00420 saveSymbolCpp (); 00421 saveSymbolJSON (); 00422 00423 // TODO slit this into another method, or merge into saveSymbolJSON 00424 // handle errors in separate 00425 qDebug() << " -> Run adms for symbol"; 00426 00427 QString vaFile; 00428 00429 // QDir prefix = QDir(QucsSettings.BinDir); 00430 00431 QDir include = QDir(QucsSettings.BinDir+"../include/qucs-core"); 00432 00433 //pick admsXml from settings 00434 QString admsXml = QucsSettings.AdmsXmlBinDir.canonicalPath(); 00435 00436 #ifdef __MINGW32__ 00437 admsXml = QDir::toNativeSeparators(admsXml+"/"+"admsXml.exe"); 00438 #else 00439 admsXml = QDir::toNativeSeparators(admsXml+"/"+"admsXml"); 00440 #endif 00441 00442 QString workDir = QucsSettings.QucsWorkDir.absolutePath(); 00443 00444 qDebug() << "App path : " << qApp->applicationDirPath(); 00445 qDebug() << "workdir" << workDir; 00446 qDebug() << "homedir" << QucsSettings.QucsHomeDir.absolutePath(); 00447 00448 vaFile = QucsSettings.QucsWorkDir.filePath(fileBase()+".va"); 00449 00450 QStringList Arguments; 00451 Arguments << QDir::toNativeSeparators(vaFile) 00452 << "-I" << QDir::toNativeSeparators(include.absolutePath()) 00453 << "-e" << QDir::toNativeSeparators(include.absFilePath("qucsMODULEguiJSONsymbol.xml")) 00454 << "-A" << "dyload"; 00455 00456 // QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); 00457 // env.insert("PATH", env.value("PATH") ); 00458 00459 QFile file(admsXml); 00460 if ( !file.exists() ){ 00461 QMessageBox::critical(this, tr("Error"), 00462 tr("Program admsXml not found: %1\n\n" 00463 "Set the admsXml location on the application settings.").arg(admsXml)); 00464 return -1; 00465 } 00466 00467 qDebug() << "Command: " << admsXml << Arguments.join(" "); 00468 00469 // need to cd into project to run admsXml? 00470 QDir::setCurrent(workDir); 00471 00472 QProcess builder; 00473 builder.setProcessChannelMode(QProcess::MergedChannels); 00474 00475 builder.start(admsXml, Arguments); 00476 00477 00478 // how to capture [warning]? need to modify admsXml? 00479 // TODO put stdout, stderr into a dock window, not messagebox 00480 if (!builder.waitForFinished()) { 00481 QString cmdString = QString("%1 %2\n\n").arg(admsXml, Arguments.join(" ")); 00482 cmdString = cmdString + builder.errorString(); 00483 QMessageBox::critical(this, tr("Error"), cmdString); 00484 } 00485 else { 00486 QString cmdString = QString("%1 %2\n\n").arg(admsXml, Arguments.join(" ")); 00487 cmdString = cmdString + builder.readAll(); 00488 QMessageBox::information(this, tr("Status"), cmdString); 00489 } 00490 00491 // Append _sym.json into _props.json, save into _symbol.json 00492 QFile f1(QucsSettings.QucsWorkDir.filePath(fileBase()+"_props.json")); 00493 QFile f2(QucsSettings.QucsWorkDir.filePath(fileBase()+"_sym.json")); 00494 f1.open(QIODevice::ReadOnly | QIODevice::Text); 00495 f2.open(QIODevice::ReadOnly | QIODevice::Text); 00496 00497 QString dat1 = QString(f1.readAll()); 00498 QString dat2 = QString(f2.readAll()); 00499 QString finalJSON = dat1.append(dat2); 00500 00501 // remove joining point 00502 finalJSON = finalJSON.replace("}{", ""); 00503 00504 QFile f3(QucsSettings.QucsWorkDir.filePath(fileBase()+"_symbol.json")); 00505 f3.open(QIODevice::WriteOnly | QIODevice::Text); 00506 QTextStream out(&f3); 00507 out << finalJSON; 00508 00509 f1.close(); 00510 f2.close(); 00511 f3.close(); 00512 00513 // TODO choose icon, default to something or provided png 00514 00515 } // if DataDisplay va 00516 } // if suffix .sym 00517 00518 return 0; 00519 } 00520 00521 // ------------------------------------------------------------- 00522 bool Schematic::loadProperties(QTextStream *stream) 00523 { 00524 bool ok = true; 00525 QString Line, cstr, nstr; 00526 while(!stream->atEnd()) { 00527 Line = stream->readLine(); 00528 if(Line.at(0) == '<') if(Line.at(1) == '/') return true; // field end ? 00529 Line = Line.trimmed(); 00530 if(Line.isEmpty()) continue; 00531 00532 if(Line.at(0) != '<') { 00533 QMessageBox::critical(0, QObject::tr("Error"), 00534 QObject::tr("Format Error:\nWrong property field limiter!")); 00535 return false; 00536 } 00537 if(Line.at(Line.length()-1) != '>') { 00538 QMessageBox::critical(0, QObject::tr("Error"), 00539 QObject::tr("Format Error:\nWrong property field limiter!")); 00540 return false; 00541 } 00542 Line = Line.mid(1, Line.length()-2); // cut off start and end character 00543 00544 cstr = Line.section('=',0,0); // property type 00545 nstr = Line.section('=',1,1); // property value 00546 if(cstr == "View") { 00547 ViewX1 = nstr.section(',',0,0).toInt(&ok); if(ok) { 00548 ViewY1 = nstr.section(',',1,1).toInt(&ok); if(ok) { 00549 ViewX2 = nstr.section(',',2,2).toInt(&ok); if(ok) { 00550 ViewY2 = nstr.section(',',3,3).toInt(&ok); if(ok) { 00551 Scale = nstr.section(',',4,4).toDouble(&ok); if(ok) { 00552 tmpViewX1 = nstr.section(',',5,5).toInt(&ok); if(ok) 00553 tmpViewY1 = nstr.section(',',6,6).toInt(&ok); }}}}} } 00554 else if(cstr == "Grid") { 00555 GridX = nstr.section(',',0,0).toInt(&ok); if(ok) { 00556 GridY = nstr.section(',',1,1).toInt(&ok); if(ok) { 00557 if(nstr.section(',',2,2).toInt(&ok) == 0) GridOn = false; 00558 else GridOn = true; }} } 00559 else if(cstr == "DataSet") DataSet = nstr; 00560 else if(cstr == "DataDisplay") DataDisplay = nstr; 00561 else if(cstr == "OpenDisplay") 00562 if(nstr.toInt(&ok) == 0) SimOpenDpl = false; 00563 else SimOpenDpl = true; 00564 else if(cstr == "Script") Script = nstr; 00565 else if(cstr == "RunScript") 00566 if(nstr.toInt(&ok) == 0) SimRunScript = false; 00567 else SimRunScript = true; 00568 else if(cstr == "showFrame") 00569 showFrame = nstr.at(0).toLatin1() - '0'; 00570 else if(cstr == "FrameText0") misc::convert2Unicode(Frame_Text0 = nstr); 00571 else if(cstr == "FrameText1") misc::convert2Unicode(Frame_Text1 = nstr); 00572 else if(cstr == "FrameText2") misc::convert2Unicode(Frame_Text2 = nstr); 00573 else if(cstr == "FrameText3") misc::convert2Unicode(Frame_Text3 = nstr); 00574 else { 00575 QMessageBox::critical(0, QObject::tr("Error"), 00576 QObject::tr("Format Error:\nUnknown property: ")+cstr); 00577 return false; 00578 } 00579 if(!ok) { 00580 QMessageBox::critical(0, QObject::tr("Error"), 00581 QObject::tr("Format Error:\nNumber expected in property field!")); 00582 return false; 00583 } 00584 } 00585 00586 QMessageBox::critical(0, QObject::tr("Error"), 00587 QObject::tr("Format Error:\n'Property' field is not closed!")); 00588 return false; 00589 } 00590 00591 // --------------------------------------------------- 00592 // Inserts a component without performing logic for wire optimization. 00593 void Schematic::simpleInsertComponent(Component *c) 00594 { 00595 Node *pn; 00596 int x, y; 00597 // connect every node of component 00598 foreach(Port *pp, c->Ports) { 00599 x = pp->x+c->cx; 00600 y = pp->y+c->cy; 00601 00602 // check if new node lies upon existing node 00603 for(pn = DocNodes.first(); pn != 0; pn = DocNodes.next()) 00604 if(pn->cx == x) if(pn->cy == y) { 00605 if (!pn->DType.isEmpty()) { 00606 pp->Type = pn->DType; 00607 } 00608 if (!pp->Type.isEmpty()) { 00609 pn->DType = pp->Type; 00610 } 00611 break; 00612 } 00613 00614 if(pn == 0) { // create new node, if no existing one lies at this position 00615 pn = new Node(x, y); 00616 DocNodes.append(pn); 00617 } 00618 pn->Connections.append(c); // connect schematic node to component node 00619 if (!pp->Type.isEmpty()) { 00620 pn->DType = pp->Type; 00621 } 00622 00623 pp->Connection = pn; // connect component node to schematic node 00624 } 00625 00626 DocComps.append(c); 00627 } 00628 00629 // ------------------------------------------------------------- 00630 bool Schematic::loadComponents(QTextStream *stream, Q3PtrList<Component> *List) 00631 { 00632 QString Line, cstr; 00633 Component *c; 00634 while(!stream->atEnd()) { 00635 Line = stream->readLine(); 00636 if(Line.at(0) == '<') if(Line.at(1) == '/') return true; 00637 Line = Line.trimmed(); 00638 if(Line.isEmpty()) continue; 00639 00641 c = getComponentFromName(Line, this); 00642 if(!c) return false; 00643 00644 if(List) { // "paste" ? 00645 int z; 00646 for(z=c->Name.length()-1; z>=0; z--) // cut off number of component name 00647 if(!c->Name.at(z).isDigit()) break; 00648 c->Name = c->Name.left(z+1); 00649 List->append(c); 00650 } 00651 else simpleInsertComponent(c); 00652 } 00653 00654 QMessageBox::critical(0, QObject::tr("Error"), 00655 QObject::tr("Format Error:\n'Component' field is not closed!")); 00656 return false; 00657 } 00658 00659 // ------------------------------------------------------------- 00660 // Inserts a wire without performing logic for optimizing. 00661 void Schematic::simpleInsertWire(Wire *pw) 00662 { 00663 Node *pn; 00664 // check if first wire node lies upon existing node 00665 for(pn = DocNodes.first(); pn != 0; pn = DocNodes.next()) 00666 if(pn->cx == pw->x1) if(pn->cy == pw->y1) break; 00667 00668 if(!pn) { // create new node, if no existing one lies at this position 00669 pn = new Node(pw->x1, pw->y1); 00670 DocNodes.append(pn); 00671 } 00672 00673 if(pw->x1 == pw->x2) if(pw->y1 == pw->y2) { 00674 pn->Label = pw->Label; // wire with length zero are just node labels 00675 if (pn->Label) { 00676 pn->Label->Type = isNodeLabel; 00677 pn->Label->pOwner = pn; 00678 } 00679 delete pw; // delete wire because this is not a wire 00680 return; 00681 } 00682 pn->Connections.append(pw); // connect schematic node to component node 00683 pw->Port1 = pn; 00684 00685 // check if second wire node lies upon existing node 00686 for(pn = DocNodes.first(); pn != 0; pn = DocNodes.next()) 00687 if(pn->cx == pw->x2) if(pn->cy == pw->y2) break; 00688 00689 if(!pn) { // create new node, if no existing one lies at this position 00690 pn = new Node(pw->x2, pw->y2); 00691 DocNodes.append(pn); 00692 } 00693 pn->Connections.append(pw); // connect schematic node to component node 00694 pw->Port2 = pn; 00695 00696 DocWires.append(pw); 00697 } 00698 00699 // ------------------------------------------------------------- 00700 bool Schematic::loadWires(QTextStream *stream, Q3PtrList<Element> *List) 00701 { 00702 Wire *w; 00703 QString Line; 00704 while(!stream->atEnd()) { 00705 Line = stream->readLine(); 00706 if(Line.at(0) == '<') if(Line.at(1) == '/') return true; 00707 Line = Line.trimmed(); 00708 if(Line.isEmpty()) continue; 00709 00710 // (Node*)4 = move all ports (later on) 00711 w = new Wire(0,0,0,0, (Node*)4,(Node*)4); 00712 if(!w->load(Line)) { 00713 QMessageBox::critical(0, QObject::tr("Error"), 00714 QObject::tr("Format Error:\nWrong 'wire' line format!")); 00715 delete w; 00716 return false; 00717 } 00718 if(List) { 00719 if(w->x1 == w->x2) if(w->y1 == w->y2) if(w->Label) { 00720 w->Label->Type = isMovingLabel; 00721 List->append(w->Label); 00722 delete w; 00723 continue; 00724 } 00725 List->append(w); 00726 if(w->Label) List->append(w->Label); 00727 } 00728 else simpleInsertWire(w); 00729 } 00730 00731 QMessageBox::critical(0, QObject::tr("Error"), 00732 QObject::tr("Format Error:\n'Wire' field is not closed!")); 00733 return false; 00734 } 00735 00736 // ------------------------------------------------------------- 00737 bool Schematic::loadDiagrams(QTextStream *stream, Q3PtrList<Diagram> *List) 00738 { 00739 Diagram *d; 00740 QString Line, cstr; 00741 while(!stream->atEnd()) { 00742 Line = stream->readLine(); 00743 if(Line.at(0) == '<') if(Line.at(1) == '/') return true; 00744 Line = Line.trimmed(); 00745 if(Line.isEmpty()) continue; 00746 00747 cstr = Line.section(' ',0,0); // diagram type 00748 if(cstr == "<Rect") d = new RectDiagram(); 00749 else if(cstr == "<Polar") d = new PolarDiagram(); 00750 else if(cstr == "<Tab") d = new TabDiagram(); 00751 else if(cstr == "<Smith") d = new SmithDiagram(); 00752 else if(cstr == "<ySmith") d = new SmithDiagram(0,0,false); 00753 else if(cstr == "<PS") d = new PSDiagram(); 00754 else if(cstr == "<SP") d = new PSDiagram(0,0,false); 00755 else if(cstr == "<Rect3D") d = new Rect3DDiagram(); 00756 else if(cstr == "<Curve") d = new CurveDiagram(); 00757 else if(cstr == "<Time") d = new TimingDiagram(); 00758 else if(cstr == "<Truth") d = new TruthDiagram(); 00759 else { 00760 QMessageBox::critical(0, QObject::tr("Error"), 00761 QObject::tr("Format Error:\nUnknown diagram!")); 00762 return false; 00763 } 00764 00765 if(!d->load(Line, stream)) { 00766 QMessageBox::critical(0, QObject::tr("Error"), 00767 QObject::tr("Format Error:\nWrong 'diagram' line format!")); 00768 delete d; 00769 return false; 00770 } 00771 List->append(d); 00772 } 00773 00774 QMessageBox::critical(0, QObject::tr("Error"), 00775 QObject::tr("Format Error:\n'Diagram' field is not closed!")); 00776 return false; 00777 } 00778 00779 // ------------------------------------------------------------- 00780 bool Schematic::loadPaintings(QTextStream *stream, Q3PtrList<Painting> *List) 00781 { 00782 Painting *p=0; 00783 QString Line, cstr; 00784 while(!stream->atEnd()) { 00785 Line = stream->readLine(); 00786 if(Line.at(0) == '<') if(Line.at(1) == '/') return true; 00787 00788 Line = Line.trimmed(); 00789 if(Line.isEmpty()) continue; 00790 if( (Line.at(0) != '<') || (Line.at(Line.length()-1) != '>')) { 00791 QMessageBox::critical(0, QObject::tr("Error"), 00792 QObject::tr("Format Error:\nWrong 'painting' line delimiter!")); 00793 return false; 00794 } 00795 Line = Line.mid(1, Line.length()-2); // cut off start and end character 00796 00797 cstr = Line.section(' ',0,0); // painting type 00798 if(cstr == "Line") p = new GraphicLine(); 00799 else if(cstr == "EArc") p = new EllipseArc(); 00800 else if(cstr == ".PortSym") p = new PortSymbol(); 00801 else if(cstr == ".ID") p = new ID_Text(); 00802 else if(cstr == "Text") p = new GraphicText(); 00803 else if(cstr == "Rectangle") p = new Rectangle(); 00804 else if(cstr == "Arrow") p = new Arrow(); 00805 else if(cstr == "Ellipse") p = new Ellipse(); 00806 else { 00807 QMessageBox::critical(0, QObject::tr("Error"), 00808 QObject::tr("Format Error:\nUnknown painting!")); 00809 return false; 00810 } 00811 00812 if(!p->load(Line)) { 00813 QMessageBox::critical(0, QObject::tr("Error"), 00814 QObject::tr("Format Error:\nWrong 'painting' line format!")); 00815 delete p; 00816 return false; 00817 } 00818 List->append(p); 00819 } 00820 00821 QMessageBox::critical(0, QObject::tr("Error"), 00822 QObject::tr("Format Error:\n'Painting' field is not closed!")); 00823 return false; 00824 } 00825 00830 bool Schematic::loadDocument() 00831 { 00832 QFile file(DocName); 00833 if(!file.open(QIODevice::ReadOnly)) { 00835 if (QucsMain) 00836 QMessageBox::critical(0, QObject::tr("Error"), 00837 QObject::tr("Cannot load document: ")+DocName); 00838 else 00839 qCritical() << "Schematic::loadDocument:" 00840 << QObject::tr("Cannot load document: ")+DocName; 00841 return false; 00842 } 00843 00844 // Keep reference to source file (the schematic file) 00845 setFileInfo(DocName); 00846 00847 QString Line; 00848 QTextStream stream(&file); 00849 00850 // read header ************************** 00851 do { 00852 if(stream.atEnd()) { 00853 file.close(); 00854 return true; 00855 } 00856 00857 Line = stream.readLine(); 00858 } while(Line.isEmpty()); 00859 00860 if(Line.left(16) != "<Qucs Schematic ") { // wrong file type ? 00861 file.close(); 00862 QMessageBox::critical(0, QObject::tr("Error"), 00863 QObject::tr("Wrong document type: ")+DocName); 00864 return false; 00865 } 00866 00867 Line = Line.mid(16, Line.length()-17); 00868 if(!misc::checkVersion(Line)) { // wrong version number ? 00869 00870 QMessageBox::StandardButton result; 00871 result = QMessageBox::warning(0, 00872 QObject::tr("Warning"), 00873 QObject::tr("Wrong document version \n" + 00874 DocName + "\n" 00875 "Try to open it anyway?"), 00876 QMessageBox::Yes|QMessageBox::No); 00877 00878 if (result==QMessageBox::No) { 00879 file.close(); 00880 return false; 00881 } 00882 00883 //QMessageBox::critical(0, QObject::tr("Error"), 00884 // QObject::tr("Wrong document version: ")+Line); 00885 } 00886 00887 // read content ************************* 00888 while(!stream.atEnd()) { 00889 Line = stream.readLine(); 00890 Line = Line.trimmed(); 00891 if(Line.isEmpty()) continue; 00892 00893 if(Line == "<Symbol>") { 00894 if(!loadPaintings(&stream, &SymbolPaints)) { 00895 file.close(); 00896 return false; 00897 } 00898 } 00899 else 00900 if(Line == "<Properties>") { 00901 if(!loadProperties(&stream)) { file.close(); return false; } } 00902 else 00903 if(Line == "<Components>") { 00904 if(!loadComponents(&stream)) { file.close(); return false; } } 00905 else 00906 if(Line == "<Wires>") { 00907 if(!loadWires(&stream)) { file.close(); return false; } } 00908 else 00909 if(Line == "<Diagrams>") { 00910 if(!loadDiagrams(&stream, &DocDiags)) { file.close(); return false; } } 00911 else 00912 if(Line == "<Paintings>") { 00913 if(!loadPaintings(&stream, &DocPaints)) { file.close(); return false; } } 00914 else { 00915 qDebug() << Line; 00916 QMessageBox::critical(0, QObject::tr("Error"), 00917 QObject::tr("File Format Error:\nUnknown field!")); 00918 file.close(); 00919 return false; 00920 } 00921 } 00922 00923 file.close(); 00924 return true; 00925 } 00926 00927 // ------------------------------------------------------------- 00928 // Creates a Qucs file format (without document properties) in the returning 00929 // string. This is used to save state for undo operation. 00930 QString Schematic::createUndoString(char Op) 00931 { 00932 Wire *pw; 00933 Diagram *pd; 00934 Painting *pp; 00935 Component *pc; 00936 00937 // Build element document. 00938 QString s = " \n"; 00939 s.replace(0,1,Op); 00940 for(pc = DocComps.first(); pc != 0; pc = DocComps.next()) 00941 s += pc->save()+"\n"; 00942 s += "</>\n"; // short end flag 00943 00944 for(pw = DocWires.first(); pw != 0; pw = DocWires.next()) 00945 s += pw->save()+"\n"; 00946 // save all labeled nodes as wires 00947 for(Node *pn = DocNodes.first(); pn != 0; pn = DocNodes.next()) 00948 if(pn->Label) s += pn->Label->save()+"\n"; 00949 s += "</>\n"; 00950 00951 for(pd = DocDiags.first(); pd != 0; pd = DocDiags.next()) 00952 s += pd->save()+"\n"; 00953 s += "</>\n"; 00954 00955 for(pp = DocPaints.first(); pp != 0; pp = DocPaints.next()) 00956 s += "<"+pp->save()+">\n"; 00957 s += "</>\n"; 00958 00959 return s; 00960 } 00961 00962 // ------------------------------------------------------------- 00963 // Same as "createUndoString(char Op)" but for symbol edit mode. 00964 QString Schematic::createSymbolUndoString(char Op) 00965 { 00966 Painting *pp; 00967 00968 // Build element document. 00969 QString s = " \n"; 00970 s.replace(0,1,Op); 00971 s += "</>\n"; // short end flag for components 00972 s += "</>\n"; // short end flag for wires 00973 s += "</>\n"; // short end flag for diagrams 00974 00975 for(pp = SymbolPaints.first(); pp != 0; pp = SymbolPaints.next()) 00976 s += "<"+pp->save()+">\n"; 00977 s += "</>\n"; 00978 00979 return s; 00980 } 00981 00982 // ------------------------------------------------------------- 00983 // Is quite similiar to "loadDocument()" but with less error checking. 00984 // Used for "undo" function. 00985 bool Schematic::rebuild(QString *s) 00986 { 00987 DocWires.clear(); // delete whole document 00988 DocNodes.clear(); 00989 DocComps.clear(); 00990 DocDiags.clear(); 00991 DocPaints.clear(); 00992 00993 QString Line; 00994 QTextStream stream(s, QIODevice::ReadOnly); 00995 Line = stream.readLine(); // skip identity byte 00996 00997 // read content ************************* 00998 if(!loadComponents(&stream)) return false; 00999 if(!loadWires(&stream)) return false; 01000 if(!loadDiagrams(&stream, &DocDiags)) return false; 01001 if(!loadPaintings(&stream, &DocPaints)) return false; 01002 01003 return true; 01004 } 01005 01006 // ------------------------------------------------------------- 01007 // Same as "rebuild(QString *s)" but for symbol edit mode. 01008 bool Schematic::rebuildSymbol(QString *s) 01009 { 01010 SymbolPaints.clear(); // delete whole document 01011 01012 QString Line; 01013 QTextStream stream(s, QIODevice::ReadOnly); 01014 Line = stream.readLine(); // skip identity byte 01015 01016 // read content ************************* 01017 Line = stream.readLine(); // skip components 01018 Line = stream.readLine(); // skip wires 01019 Line = stream.readLine(); // skip diagrams 01020 if(!loadPaintings(&stream, &SymbolPaints)) return false; 01021 01022 return true; 01023 } 01024 01025 01026 // *************************************************************** 01027 // ***** ***** 01028 // ***** Functions to create netlist ***** 01029 // ***** ***** 01030 // *************************************************************** 01031 01032 void Schematic::createNodeSet(QStringList& Collect, int& countInit, 01033 Conductor *pw, Node *p1) 01034 { 01035 if(pw->Label) 01036 if(!pw->Label->initValue.isEmpty()) 01037 Collect.append("NodeSet:NS" + QString::number(countInit++) + " " + 01038 p1->Name + " U=\"" + pw->Label->initValue + "\""); 01039 } 01040 01041 // --------------------------------------------------- 01042 void Schematic::throughAllNodes(bool User, QStringList& Collect, 01043 int& countInit) 01044 { 01045 Node *pn; 01046 int z=0; 01047 01048 for(pn = DocNodes.first(); pn != 0; pn = DocNodes.next()) { 01049 if(pn->Name.isEmpty() == User) { 01050 continue; // already named ? 01051 } 01052 if(!User) { 01053 if(isAnalog) 01054 pn->Name = "_net"; 01055 else 01056 pn->Name = "net_net"; // VHDL names must not begin with '_' 01057 pn->Name += QString::number(z++); // create numbered node name 01058 } 01059 else if(pn->State) { 01060 continue; // already worked on 01061 } 01062 01063 if(isAnalog) createNodeSet(Collect, countInit, pn, pn); 01064 01065 pn->State = 1; 01066 propagateNode(Collect, countInit, pn); 01067 } 01068 } 01069 01070 // ---------------------------------------------------------- 01071 // Checks whether this file is a qucs file and whether it is an subcircuit. 01072 // It returns the number of subcircuit ports. 01073 int Schematic::testFile(const QString& DocName) 01074 { 01075 QFile file(DocName); 01076 if(!file.open(QIODevice::ReadOnly)) { 01077 return -1; 01078 } 01079 01080 QString Line; 01081 // ......................................... 01082 // To strongly speed up the file read operation the whole file is 01083 // read into the memory in one piece. 01084 QTextStream ReadWhole(&file); 01085 QString FileString = ReadWhole.read(); 01086 file.close(); 01087 QTextStream stream(&FileString, QIODevice::ReadOnly); 01088 01089 01090 // read header ........................ 01091 do { 01092 if(stream.atEnd()) { 01093 file.close(); 01094 return -2; 01095 } 01096 Line = stream.readLine(); 01097 Line = Line.trimmed(); 01098 } while(Line.isEmpty()); 01099 01100 if(Line.left(16) != "<Qucs Schematic ") { // wrong file type ? 01101 file.close(); 01102 return -3; 01103 } 01104 01105 Line = Line.mid(16, Line.length()-17); 01106 if(!misc::checkVersion(Line)) { // wrong version number ? 01107 if (!QucsSettings.IgnoreFutureVersion) { 01108 file.close(); 01109 return -4; 01110 } 01111 //file.close(); 01112 //return -4; 01113 } 01114 01115 // read content .................... 01116 while(!stream.atEnd()) { 01117 Line = stream.readLine(); 01118 if(Line == "<Components>") break; 01119 } 01120 01121 int z=0; 01122 while(!stream.atEnd()) { 01123 Line = stream.readLine(); 01124 if(Line == "</Components>") { 01125 file.close(); 01126 return z; // return number of ports 01127 } 01128 01129 Line = Line.trimmed(); 01130 QString s = Line.section(' ',0,0); // component type 01131 if(s == "<Port") z++; 01132 } 01133 return -5; // component field not closed 01134 } 01135 01136 // --------------------------------------------------- 01137 // Collects the signal names for digital simulations. 01138 void Schematic::collectDigitalSignals(void) 01139 { 01140 Node *pn; 01141 01142 for(pn = DocNodes.first(); pn != 0; pn = DocNodes.next()) { 01143 DigMap::Iterator it = Signals.find(pn->Name); 01144 if(it == Signals.end()) { // avoid redeclaration of signal 01145 Signals.insert(pn->Name, DigSignal(pn->Name, pn->DType)); 01146 } else if (!pn->DType.isEmpty()) { 01147 it.data().Type = pn->DType; 01148 } 01149 } 01150 } 01151 01152 // --------------------------------------------------- 01153 // Propagates the given node to connected component ports. 01154 void Schematic::propagateNode(QStringList& Collect, 01155 int& countInit, Node *pn) 01156 { 01157 bool setName=false; 01158 Q3PtrList<Node> Cons; 01159 Node *p2; 01160 Wire *pw; 01161 Element *pe; 01162 01163 Cons.append(pn); 01164 for(p2 = Cons.first(); p2 != 0; p2 = Cons.next()) 01165 for(pe = p2->Connections.first(); pe != 0; pe = p2->Connections.next()) 01166 if(pe->Type == isWire) { 01167 pw = (Wire*)pe; 01168 if(p2 != pw->Port1) { 01169 if(pw->Port1->Name.isEmpty()) { 01170 pw->Port1->Name = pn->Name; 01171 pw->Port1->State = 1; 01172 Cons.append(pw->Port1); 01173 setName = true; 01174 } 01175 } 01176 else { 01177 if(pw->Port2->Name.isEmpty()) { 01178 pw->Port2->Name = pn->Name; 01179 pw->Port2->State = 1; 01180 Cons.append(pw->Port2); 01181 setName = true; 01182 } 01183 } 01184 if(setName) { 01185 Cons.findRef(p2); // back to current Connection 01186 if (isAnalog) createNodeSet(Collect, countInit, pw, pn); 01187 setName = false; 01188 } 01189 } 01190 Cons.clear(); 01191 } 01192 01193 #include <iostream> 01194 01206 bool Schematic::throughAllComps(QTextStream *stream, int& countInit, 01207 QStringList& Collect, QPlainTextEdit *ErrText, int NumPorts) 01208 { 01209 bool r; 01210 QString s; 01211 01212 // give the ground nodes the name "gnd", and insert subcircuits etc. 01213 Q3PtrListIterator<Component> it(DocComps); 01214 Component *pc; 01215 while((pc = it.current()) != 0) { 01216 ++it; 01217 if(pc->isActive != COMP_IS_ACTIVE) continue; 01218 01219 // check analog/digital typed components 01220 if(isAnalog) { 01221 if((pc->Type & isAnalogComponent) == 0) { 01222 ErrText->appendPlainText(QObject::tr("ERROR: Component \"%1\" has no analog model.").arg(pc->Name)); 01223 return false; 01224 } 01225 } else { 01226 if((pc->Type & isDigitalComponent) == 0) { 01227 ErrText->appendPlainText(QObject::tr("ERROR: Component \"%1\" has no digital model.").arg(pc->Name)); 01228 return false; 01229 } 01230 } 01231 01232 // handle ground symbol 01233 if(pc->Model == "GND") { 01234 pc->Ports.first()->Connection->Name = "gnd"; 01235 continue; 01236 } 01237 01238 // handle subcircuits 01239 if(pc->Model == "Sub") 01240 { 01241 int i; 01242 // tell the subcircuit it belongs to this schematic 01243 pc->setSchematic (this); 01244 QString f = pc->getSubcircuitFile(); 01245 SubMap::Iterator it = FileList.find(f); 01246 if(it != FileList.end()) 01247 { 01248 if (!it.data().PortTypes.isEmpty()) 01249 { 01250 i = 0; 01251 // apply in/out signal types of subcircuit 01252 foreach(Port *pp, pc->Ports) 01253 { 01254 pp->Type = it.data().PortTypes[i]; 01255 pp->Connection->DType = pp->Type; 01256 i++; 01257 } 01258 } 01259 continue; // insert each subcircuit just one time 01260 } 01261 01262 // The subcircuit has not previously been added 01263 SubFile sub = SubFile("SCH", f); 01264 FileList.insert(f, sub); 01265 01266 01267 // load subcircuit schematic 01268 s = pc->Props.first()->Value; 01269 Schematic *d = new Schematic(0, pc->getSubcircuitFile()); 01270 if(!d->loadDocument()) // load document if possible 01271 { 01272 delete d; 01274 QString message = QObject::tr("ERROR: Cannot load subcircuit \"%1\".").arg(s); 01275 if (QucsMain) // GUI is running 01276 ErrText->appendPlainText(message); 01277 else // command line 01278 qCritical() << "Schematic::throughAllComps" << message; 01279 return false; 01280 } 01281 d->DocName = s; 01282 d->isVerilog = isVerilog; 01283 d->isAnalog = isAnalog; 01284 d->creatingLib = creatingLib; 01285 r = d->createSubNetlist(stream, countInit, Collect, ErrText, NumPorts); 01286 if (r) 01287 { 01288 i = 0; 01289 // save in/out signal types of subcircuit 01290 foreach(Port *pp, pc->Ports) 01291 { 01292 //if(i>=d->PortTypes.count())break; 01293 pp->Type = d->PortTypes[i]; 01294 pp->Connection->DType = pp->Type; 01295 i++; 01296 } 01297 sub.PortTypes = d->PortTypes; 01298 FileList.replace(f, sub); 01299 } 01300 delete d; 01301 if(!r) 01302 { 01303 return false; 01304 } 01305 continue; 01306 } // if(pc->Model == "Sub") 01307 01308 // handle library symbols 01309 if(pc->Model == "Lib") { 01310 if(creatingLib) { 01311 ErrText->appendPlainText( 01312 QObject::tr("WARNING: Skipping library component \"%1\"."). 01313 arg(pc->Name)); 01314 continue; 01315 } 01316 s = pc->getSubcircuitFile() + "/" + pc->Props.at(1)->Value; 01317 SubMap::Iterator it = FileList.find(s); 01318 if(it != FileList.end()) 01319 continue; // insert each library subcircuit just one time 01320 FileList.insert(s, SubFile("LIB", s)); 01321 01322 if(isAnalog) 01323 r = ((LibComp*)pc)->createSubNetlist(stream, Collect, 1); 01324 else { 01325 if(isVerilog) 01326 r = ((LibComp*)pc)->createSubNetlist(stream, Collect, 4); 01327 else 01328 r = ((LibComp*)pc)->createSubNetlist(stream, Collect, 2); 01329 } 01330 if(!r) { 01331 ErrText->appendPlainText( 01332 QObject::tr("ERROR: Cannot load library component \"%1\"."). 01333 arg(pc->Name)); 01334 return false; 01335 } 01336 continue; 01337 } 01338 01339 // handle SPICE subcircuit components 01340 if(pc->Model == "SPICE") { 01341 s = pc->Props.first()->Value; 01342 // tell the spice component it belongs to this schematic 01343 pc->setSchematic (this); 01344 if(s.isEmpty()) { 01345 ErrText->appendPlainText(QObject::tr("ERROR: No file name in SPICE component \"%1\"."). 01346 arg(pc->Name)); 01347 return false; 01348 } 01349 QString f = pc->getSubcircuitFile(); 01350 SubMap::Iterator it = FileList.find(f); 01351 if(it != FileList.end()) 01352 continue; // insert each spice component just one time 01353 FileList.insert(f, SubFile("CIR", f)); 01354 01355 SpiceFile *sf = (SpiceFile*)pc; 01356 r = sf->createSubNetlist(stream); 01357 ErrText->appendPlainText(sf->getErrorText()); 01358 if(!r) return false; 01359 continue; 01360 } 01361 01362 // handle digital file subcircuits 01363 if(pc->Model == "VHDL" || pc->Model == "Verilog") { 01364 if(isVerilog && pc->Model == "VHDL") 01365 continue; 01366 if(!isVerilog && pc->Model == "Verilog") 01367 continue; 01368 s = pc->Props.getFirst()->Value; 01369 if(s.isEmpty()) { 01370 ErrText->appendPlainText(QObject::tr("ERROR: No file name in %1 component \"%2\"."). 01371 arg(pc->Model). 01372 arg(pc->Name)); 01373 return false; 01374 } 01375 QString f = pc->getSubcircuitFile(); 01376 SubMap::Iterator it = FileList.find(f); 01377 if(it != FileList.end()) 01378 continue; // insert each vhdl/verilog component just one time 01379 s = ((pc->Model == "VHDL") ? "VHD" : "VER"); 01380 FileList.insert(f, SubFile(s, f)); 01381 01382 if(pc->Model == "VHDL") { 01383 VHDL_File *vf = (VHDL_File*)pc; 01384 r = vf->createSubNetlist(stream); 01385 ErrText->appendPlainText(vf->getErrorText()); 01386 if(!r) return false; 01387 } 01388 if(pc->Model == "Verilog") { 01389 Verilog_File *vf = (Verilog_File*)pc; 01390 r = vf->createSubNetlist(stream); 01391 ErrText->appendPlainText(vf->getErrorText()); 01392 if(!r) return false; 01393 } 01394 continue; 01395 } 01396 } 01397 return true; 01398 } 01399 01400 // --------------------------------------------------- 01401 // Follows the wire lines in order to determine the node names for 01402 // each component. Output into "stream", NodeSets are collected in 01403 // "Collect" and counted with "countInit". 01404 bool Schematic::giveNodeNames(QTextStream *stream, int& countInit, 01405 QStringList& Collect, QPlainTextEdit *ErrText, int NumPorts) 01406 { 01407 // delete the node names 01408 for(Node *pn = DocNodes.first(); pn != 0; pn = DocNodes.next()) { 01409 pn->State = 0; 01410 if(pn->Label) { 01411 if(isAnalog) 01412 pn->Name = pn->Label->Name; 01413 else 01414 pn->Name = "net" + pn->Label->Name; 01415 } 01416 else pn->Name = ""; 01417 } 01418 01419 // set the wire names to the connected node 01420 for(Wire *pw = DocWires.first(); pw != 0; pw = DocWires.next()) 01421 if(pw->Label != 0) { 01422 if(isAnalog) 01423 pw->Port1->Name = pw->Label->Name; 01424 else // avoid to use reserved VHDL words 01425 pw->Port1->Name = "net" + pw->Label->Name; 01426 } 01427 01428 // go through components 01429 if(!throughAllComps(stream, countInit, Collect, ErrText, NumPorts)) 01430 return false; 01431 01432 // work on named nodes first in order to preserve the user given names 01433 throughAllNodes(true, Collect, countInit); 01434 01435 // give names to the remaining (unnamed) nodes 01436 throughAllNodes(false, Collect, countInit); 01437 01438 if(!isAnalog) // collect all node names for VHDL signal declaration 01439 collectDigitalSignals(); 01440 01441 return true; 01442 } 01443 01444 // --------------------------------------------------- 01445 bool Schematic::createLibNetlist(QTextStream *stream, QPlainTextEdit *ErrText, 01446 int NumPorts) 01447 { 01448 int countInit = 0; 01449 QStringList Collect; 01450 Collect.clear(); 01451 FileList.clear(); 01452 Signals.clear(); 01453 // Apply node names and collect subcircuits and file include 01454 creatingLib = true; 01455 if(!giveNodeNames(stream, countInit, Collect, ErrText, NumPorts)) { 01456 creatingLib = false; 01457 return false; 01458 } 01459 creatingLib = false; 01460 01461 // Marking start of actual top-level subcircuit 01462 QString c; 01463 if(!isAnalog) { 01464 if (isVerilog) 01465 c = "///"; 01466 else 01467 c = "---"; 01468 } 01469 else c = "###"; 01470 (*stream) << "\n" << c << " TOP LEVEL MARK " << c << "\n"; 01471 01472 // Emit subcircuit components 01473 createSubNetlistPlain(stream, ErrText, NumPorts); 01474 01475 Signals.clear(); // was filled in "giveNodeNames()" 01476 return true; 01477 } 01478 01479 //#define VHDL_SIGNAL_TYPE "bit" 01480 //#define VHDL_LIBRARIES "" 01481 #define VHDL_SIGNAL_TYPE "std_logic" 01482 #define VHDL_LIBRARIES "\nlibrary ieee;\nuse ieee.std_logic_1164.all;\n" 01483 01484 // --------------------------------------------------- 01485 void Schematic::createSubNetlistPlain(QTextStream *stream, QPlainTextEdit *ErrText, 01486 int NumPorts) 01487 { 01488 int i, z; 01489 QString s; 01490 QStringList SubcircuitPortNames; 01491 QStringList SubcircuitPortTypes; 01492 QStringList InPorts; 01493 QStringList OutPorts; 01494 QStringList InOutPorts; 01495 QStringList::iterator it_name; 01496 QStringList::iterator it_type; 01497 Component *pc; 01498 01499 // probably creating a library currently 01500 QTextStream * tstream = stream; 01501 QFile ofile; 01502 if(creatingLib) { 01503 QString f = misc::properAbsFileName(DocName) + ".lst"; 01504 ofile.setFileName(f); 01505 if(!ofile.open(IO_WriteOnly)) { 01506 ErrText->appendPlainText(tr("ERROR: Cannot create library file \"%s\".").arg(f)); 01507 return; 01508 } 01509 tstream = new QTextStream(&ofile); 01510 } 01511 01512 // collect subcircuit ports and sort their node names into 01513 // "SubcircuitPortNames" 01514 PortTypes.clear(); 01515 for(pc = DocComps.first(); pc != 0; pc = DocComps.next()) { 01516 if(pc->Model.at(0) == '.') { // no simulations in subcircuits 01517 ErrText->appendPlainText( 01518 QObject::tr("WARNING: Ignore simulation component in subcircuit \"%1\".").arg(DocName)+"\n"); 01519 continue; 01520 } 01521 else if(pc->Model == "Port") { 01522 i = pc->Props.first()->Value.toInt(); 01523 for(z=SubcircuitPortNames.size(); z<i; z++) { // add empty port names 01524 SubcircuitPortNames.append(" "); 01525 SubcircuitPortTypes.append(" "); 01526 } 01527 it_name = SubcircuitPortNames.begin(); 01528 it_type = SubcircuitPortTypes.begin(); 01529 for(int n=1;n<i;n++) 01530 { 01531 it_name++; 01532 it_type++; 01533 } 01534 (*it_name) = pc->Ports.first()->Connection->Name; 01535 DigMap::Iterator it = Signals.find(*it_name); 01536 if(it!=Signals.end()) 01537 (*it_type) = it.data().Type; 01538 // propagate type to port symbol 01539 pc->Ports.first()->Connection->DType = *it_type; 01540 01541 if(!isAnalog) { 01542 if (isVerilog) { 01543 Signals.erase(*it_name); // remove node name 01544 switch(pc->Props.at(1)->Value.at(0).toLatin1()) { 01545 case 'a': 01546 InOutPorts.append(*it_name); 01547 break; 01548 case 'o': 01549 OutPorts.append(*it_name); 01550 break; 01551 default: 01552 InPorts.append(*it_name); 01553 } 01554 } 01555 else { 01556 // remove node name of output port 01557 Signals.erase(*it_name); 01558 switch(pc->Props.at(1)->Value.at(0).toLatin1()) { 01559 case 'a': 01560 (*it_name) += " : inout"; // attribute "analog" is "inout" 01561 break; 01562 case 'o': // output ports need workaround 01563 Signals.insert(*it_name, DigSignal(*it_name, *it_type)); 01564 (*it_name) = "net_out" + (*it_name); 01565 // no "break;" here !!! 01566 default: 01567 (*it_name) += " : " + pc->Props.at(1)->Value; 01568 } 01569 (*it_name) += " " + ((*it_type).isEmpty() ? 01570 VHDL_SIGNAL_TYPE : (*it_type)); 01571 } 01572 } 01573 } 01574 } 01575 01576 // remove empty subcircuit ports (missing port numbers) 01577 for(it_name = SubcircuitPortNames.begin(), 01578 it_type = SubcircuitPortTypes.begin(); 01579 it_name != SubcircuitPortNames.end(); ) { 01580 if(*it_name == " ") { 01581 it_name = SubcircuitPortNames.remove(it_name); 01582 it_type = SubcircuitPortTypes.remove(it_type); 01583 } else { 01584 PortTypes.append(*it_type); 01585 it_name++; 01586 it_type++; 01587 } 01588 } 01589 01590 QString f = misc::properFileName(DocName); 01591 QString Type = misc::properName(f); 01592 01593 Painting *pi; 01594 if(isAnalog) { 01595 // ..... analog subcircuit ................................... 01596 (*tstream) << "\n.Def:" << Type << " " << SubcircuitPortNames.join(" "); 01597 for(pi = SymbolPaints.first(); pi != 0; pi = SymbolPaints.next()) 01598 if(pi->Name == ".ID ") { 01599 ID_Text *pid = (ID_Text*)pi; 01600 QList<SubParameter *>::const_iterator it; 01601 for(it = pid->Parameter.constBegin(); it != pid->Parameter.constEnd(); it++) { 01602 s = (*it)->Name; // keep 'Name' unchanged 01603 (*tstream) << " " << s.replace("=", "=\"") << '"'; 01604 } 01605 break; 01606 } 01607 (*tstream) << '\n'; 01608 01609 // write all components with node names into netlist file 01610 for(pc = DocComps.first(); pc != 0; pc = DocComps.next()) 01611 (*tstream) << pc->getNetlist(); 01612 01613 (*tstream) << ".Def:End\n"; 01614 01615 } 01616 else { 01617 if (isVerilog) { 01618 // ..... digital subcircuit ................................... 01619 (*tstream) << "\nmodule Sub_" << Type << " (" 01620 << SubcircuitPortNames.join(", ") << ");\n"; 01621 01622 // subcircuit in/out connections 01623 if(!InPorts.isEmpty()) 01624 (*tstream) << " input " << InPorts.join(", ") << ";\n"; 01625 if(!OutPorts.isEmpty()) 01626 (*tstream) << " output " << OutPorts.join(", ") << ";\n"; 01627 if(!InOutPorts.isEmpty()) 01628 (*tstream) << " inout " << InOutPorts.join(", ") << ";\n"; 01629 01630 // subcircuit connections 01631 if(!Signals.isEmpty()) { 01632 QList<DigSignal> values = Signals.values(); 01633 QList<DigSignal>::const_iterator it; 01634 for (it = values.constBegin(); it != values.constEnd(); ++it) { 01635 (*tstream) << " wire " << (*it).Name << ";\n"; 01636 } 01637 } 01638 (*tstream) << "\n"; 01639 01640 // subcircuit parameters 01641 for(pi = SymbolPaints.first(); pi != 0; pi = SymbolPaints.next()) 01642 if(pi->Name == ".ID ") { 01643 QList<SubParameter *>::const_iterator it; 01644 ID_Text *pid = (ID_Text*)pi; 01645 for(it = pid->Parameter.constBegin(); it != pid->Parameter.constEnd(); it++) { 01646 s = (*it)->Name.section('=', 0,0); 01647 QString v = misc::Verilog_Param((*it)->Name.section('=', 1,1)); 01648 (*tstream) << " parameter " << s << " = " << v << ";\n"; 01649 } 01650 (*tstream) << "\n"; 01651 break; 01652 } 01653 01654 // write all equations into netlist file 01655 for(pc = DocComps.first(); pc != 0; pc = DocComps.next()) { 01656 if(pc->Model == "Eqn") { 01657 (*tstream) << pc->get_Verilog_Code(NumPorts); 01658 } 01659 } 01660 01661 if(Signals.find("gnd") != Signals.end()) 01662 (*tstream) << " assign gnd = 0;\n"; // should appear only once 01663 01664 // write all components into netlist file 01665 for(pc = DocComps.first(); pc != 0; pc = DocComps.next()) { 01666 if(pc->Model != "Eqn") { 01667 s = pc->get_Verilog_Code(NumPorts); 01668 if(s.length()>0 && s.at(0) == '\xA7') { //section symbol 01669 ErrText->appendPlainText(s.mid(1)); 01670 } 01671 else (*tstream) << s; 01672 } 01673 } 01674 01675 (*tstream) << "endmodule\n"; 01676 } else { 01677 // ..... digital subcircuit ................................... 01678 (*tstream) << VHDL_LIBRARIES; 01679 (*tstream) << "entity Sub_" << Type << " is\n" 01680 << " port (" 01681 << SubcircuitPortNames.join(";\n ") << ");\n"; 01682 01683 for(pi = SymbolPaints.first(); pi != 0; pi = SymbolPaints.next()) 01684 if(pi->Name == ".ID ") { 01685 ID_Text *pid = (ID_Text*)pi; 01686 QList<SubParameter *>::const_iterator it; 01687 01688 (*tstream) << " generic ("; 01689 01690 for(it = pid->Parameter.constBegin(); it != pid->Parameter.constEnd(); it++) { 01691 s = (*it)->Name; 01692 QString t = (*it)->Type.isEmpty() ? "real" : (*it)->Type; 01693 (*tstream) << s.replace("=", " : "+t+" := ") << ";\n "; 01694 } 01695 01696 (*tstream) << ");\n"; 01697 break; 01698 } 01699 01700 (*tstream) << "end entity;\n" 01701 << "use work.all;\n" 01702 << "architecture Arch_Sub_" << Type << " of Sub_" << Type 01703 << " is\n"; 01704 01705 if(!Signals.isEmpty()) { 01706 QList<DigSignal> values = Signals.values(); 01707 QList<DigSignal>::const_iterator it; 01708 for (it = values.constBegin(); it != values.constEnd(); ++it) { 01709 (*tstream) << " signal " << (*it).Name << " : " 01710 << ((*it).Type.isEmpty() ? 01711 VHDL_SIGNAL_TYPE : (*it).Type) << ";\n"; 01712 } 01713 } 01714 01715 // write all equations into netlist file 01716 for(pc = DocComps.first(); pc != 0; pc = DocComps.next()) { 01717 if(pc->Model == "Eqn") { 01718 ErrText->appendPlainText( 01719 QObject::tr("WARNING: Equations in \"%1\" are 'time' typed."). 01720 arg(pc->Name)); 01721 (*tstream) << pc->get_VHDL_Code(NumPorts); 01722 } 01723 } 01724 01725 (*tstream) << "begin\n"; 01726 01727 if(Signals.find("gnd") != Signals.end()) 01728 (*tstream) << " gnd <= '0';\n"; // should appear only once 01729 01730 // write all components into netlist file 01731 for(pc = DocComps.first(); pc != 0; pc = DocComps.next()) { 01732 if(pc->Model != "Eqn") { 01733 s = pc->get_VHDL_Code(NumPorts); 01734 if(s.length()>0 && s.at(0) == '\xA7') { //section symbol 01735 ErrText->appendPlainText(s.mid(1)); 01736 } 01737 else (*tstream) << s; 01738 } 01739 } 01740 01741 (*tstream) << "end architecture;\n"; 01742 } 01743 } 01744 01745 // close file 01746 if(creatingLib) { 01747 ofile.close(); 01748 delete tstream; 01749 } 01750 } 01751 // --------------------------------------------------- 01752 // Write the netlist as subcircuit to the text stream 'stream'. 01753 bool Schematic::createSubNetlist(QTextStream *stream, int& countInit, 01754 QStringList& Collect, QPlainTextEdit *ErrText, int NumPorts) 01755 { 01756 // int Collect_count = Collect.count(); // position for this subcircuit 01757 01758 // TODO: NodeSets have to be put into the subcircuit block. 01759 if(!giveNodeNames(stream, countInit, Collect, ErrText, NumPorts)) 01760 return false; 01761 01762 /* Example for TODO 01763 for(it = Collect.at(Collect_count); it != Collect.end(); ) 01764 if((*it).left(4) == "use ") { // output all subcircuit uses 01765 (*stream) << (*it); 01766 it = Collect.remove(it); 01767 } 01768 else it++;*/ 01769 01770 // Emit subcircuit components 01771 createSubNetlistPlain(stream, ErrText, NumPorts); 01772 01773 Signals.clear(); // was filled in "giveNodeNames()" 01774 return true; 01775 } 01776 01777 // --------------------------------------------------- 01778 // Determines the node names and writes subcircuits into netlist file. 01779 int Schematic::prepareNetlist(QTextStream& stream, QStringList& Collect, 01780 QPlainTextEdit *ErrText) 01781 { 01782 if(showBias > 0) showBias = -1; // do not show DC bias anymore 01783 01784 isVerilog = false; 01785 isAnalog = true; 01786 bool isTruthTable = false; 01787 int allTypes = 0, NumPorts = 0; 01788 01789 // Detect simulation domain (analog/digital) by looking at component types. 01790 for(Component *pc = DocComps.first(); pc != 0; pc = DocComps.next()) { 01791 if(pc->isActive == COMP_IS_OPEN) continue; 01792 if(pc->Model.at(0) == '.') { 01793 if(pc->Model == ".Digi") { 01794 if(allTypes & isDigitalComponent) { 01795 ErrText->appendPlainText( 01796 QObject::tr("ERROR: Only one digital simulation allowed.")); 01797 return -10; 01798 } 01799 if(pc->Props.getFirst()->Value != "TimeList") 01800 isTruthTable = true; 01801 if(pc->Props.getLast()->Value != "VHDL") 01802 isVerilog = true; 01803 allTypes |= isDigitalComponent; 01804 isAnalog = false; 01805 } 01806 else allTypes |= isAnalogComponent; 01807 if((allTypes & isComponent) == isComponent) { 01808 ErrText->appendPlainText( 01809 QObject::tr("ERROR: Analog and digital simulations cannot be mixed.")); 01810 return -10; 01811 } 01812 } 01813 else if(pc->Model == "DigiSource") NumPorts++; 01814 } 01815 01816 if((allTypes & isAnalogComponent) == 0) { 01817 if(allTypes == 0) { 01818 // If no simulation exists, assume analog simulation. There may 01819 // be a simulation within a SPICE file. Otherwise Qucsator will 01820 // output an error. 01821 isAnalog = true; 01822 allTypes |= isAnalogComponent; 01823 NumPorts = -1; 01824 } 01825 else { 01826 if(NumPorts < 1 && isTruthTable) { 01827 ErrText->appendPlainText( 01828 QObject::tr("ERROR: Digital simulation needs at least one digital source.")); 01829 return -10; 01830 } 01831 if(!isTruthTable) NumPorts = 0; 01832 } 01833 } 01834 else { 01835 NumPorts = -1; 01836 isAnalog = true; 01837 } 01838 01839 // first line is documentation 01840 if(allTypes & isAnalogComponent) 01841 stream << "#"; 01842 else if (isVerilog) 01843 stream << "//"; 01844 else 01845 stream << "--"; 01846 stream << " Qucs " << PACKAGE_VERSION << " " << DocName << "\n"; 01847 01848 // set timescale property for verilog schematics 01849 if (isVerilog) { 01850 stream << "\n`timescale 1ps/100fs\n"; 01851 } 01852 01853 int countInit = 0; // counts the nodesets to give them unique names 01854 if(!giveNodeNames(&stream, countInit, Collect, ErrText, NumPorts)) 01855 return -10; 01856 01857 if(allTypes & isAnalogComponent) 01858 return NumPorts; 01859 01860 if (!isVerilog) { 01861 stream << VHDL_LIBRARIES; 01862 stream << "entity TestBench is\n" 01863 << "end entity;\n" 01864 << "use work.all;\n"; 01865 } 01866 return NumPorts; 01867 } 01868 01869 // --------------------------------------------------- 01870 // Write the beginning of digital netlist to the text stream 'stream'. 01871 void Schematic::beginNetlistDigital(QTextStream& stream) 01872 { 01873 if (isVerilog) { 01874 stream << "module TestBench ();\n"; 01875 QList<DigSignal> values = Signals.values(); 01876 QList<DigSignal>::const_iterator it; 01877 for (it = values.constBegin(); it != values.constEnd(); ++it) { 01878 stream << " wire " << (*it).Name << ";\n"; 01879 } 01880 stream << "\n"; 01881 } else { 01882 stream << "architecture Arch_TestBench of TestBench is\n"; 01883 QList<DigSignal> values = Signals.values(); 01884 QList<DigSignal>::const_iterator it; 01885 for (it = values.constBegin(); it != values.constEnd(); ++it) { 01886 stream << " signal " << (*it).Name << " : " 01887 << ((*it).Type.isEmpty() ? 01888 VHDL_SIGNAL_TYPE : (*it).Type) << ";\n"; 01889 } 01890 stream << "begin\n"; 01891 } 01892 01893 if(Signals.find("gnd") != Signals.end()) { 01894 if (isVerilog) { 01895 stream << " assign gnd = 0;\n"; 01896 } else { 01897 stream << " gnd <= '0';\n"; // should appear only once 01898 } 01899 } 01900 } 01901 01902 // --------------------------------------------------- 01903 // Write the end of digital netlist to the text stream 'stream'. 01904 void Schematic::endNetlistDigital(QTextStream& stream) 01905 { 01906 if (isVerilog) { 01907 } else { 01908 stream << "end architecture;\n"; 01909 } 01910 } 01911 01912 // --------------------------------------------------- 01913 // write all components with node names into the netlist file 01914 QString Schematic::createNetlist(QTextStream& stream, int NumPorts) 01915 { 01916 if(!isAnalog) { 01917 beginNetlistDigital(stream); 01918 } 01919 01920 Signals.clear(); // was filled in "giveNodeNames()" 01921 FileList.clear(); 01922 01923 QString s, Time; 01924 for(Component *pc = DocComps.first(); pc != 0; pc = DocComps.next()) { 01925 if(isAnalog) { 01926 s = pc->getNetlist(); 01927 } 01928 else { 01929 if(pc->Model == ".Digi" && pc->isActive) { // simulation component ? 01930 if(NumPorts > 0) { // truth table simulation ? 01931 if (isVerilog) 01932 Time = QString::number((1 << NumPorts)); 01933 else 01934 Time = QString::number((1 << NumPorts) - 1) + " ns"; 01935 } else { 01936 Time = pc->Props.at(1)->Value; 01937 if (isVerilog) { 01938 if(!misc::Verilog_Time(Time, pc->Name)) return Time; 01939 } else { 01940 if(!misc::VHDL_Time(Time, pc->Name)) return Time; // wrong time format 01941 } 01942 } 01943 } 01944 if (isVerilog) { 01945 s = pc->get_Verilog_Code(NumPorts); 01946 } else { 01947 s = pc->get_VHDL_Code(NumPorts); 01948 } 01949 if (s.length()>0 && s.at(0) == '\xA7'){ 01950 return s; // return error 01951 } 01952 } 01953 stream << s; 01954 } 01955 01956 if(!isAnalog) { 01957 endNetlistDigital(stream); 01958 } 01959 01960 return Time; 01961 }