From 6adc782cffd5cab1818603f5ce7eb36f05e3e417 Mon Sep 17 00:00:00 2001 From: Vadim Kuznetsov Date: Sat, 18 Jan 2025 18:39:35 +0300 Subject: [PATCH 1/3] Implement attaching of SPICE libraries to Qucs XML libraries SPICE libraries referenced by SpiceLibComp are copied to the the subdirectory when creating a library from project. --- qucs/components/component.h | 1 + qucs/components/libcomp.cpp | 26 +++++++++++++++++++++ qucs/components/libcomp.h | 1 + qucs/dialogs/librarydialog.cpp | 11 +++++++++ qucs/extsimkernels/abstractspicekernel.cpp | 27 ++++++++++++++++++++++ qucs/extsimkernels/abstractspicekernel.h | 1 + qucs/spicecomponents/sp_include.cpp | 13 +++++++++++ qucs/spicecomponents/sp_include.h | 1 + qucs/spicecomponents/spicelibcomp.cpp | 8 +++++++ qucs/spicecomponents/spicelibcomp.h | 1 + 10 files changed, 90 insertions(+) diff --git a/qucs/components/component.h b/qucs/components/component.h index cf553ae07..092d860af 100644 --- a/qucs/components/component.h +++ b/qucs/components/component.h @@ -50,6 +50,7 @@ class Component : public Element { virtual QString getProbeVariable(bool isXyce = false); virtual QString getSpiceModel(); virtual QString getSpiceLibrary() { return QString(); } + virtual QStringList getSpiceLibraryFiles() { return QStringList(); } virtual QString getNgspiceBeforeSim(QString sim, int lvl=0); virtual QString getNgspiceAfterSim(QString sim, int lvl=0); virtual QString getVAvariables() {return QString();}; diff --git a/qucs/components/libcomp.cpp b/qucs/components/libcomp.cpp index 12b2fc073..e2f4fd933 100644 --- a/qucs/components/libcomp.cpp +++ b/qucs/components/libcomp.cpp @@ -412,3 +412,29 @@ QStringList LibComp::getAttachedMOD() } return mod_lst; } + +QString LibComp::getSpiceLibrary() +{ + QStringList files; + QString content; + QStringList includes,attach; + + int r = loadSection("Spice",content,&includes,&attach); + if (r<0) { + return QString(); + } + for (const auto &file : attach) { + if (file.endsWith(".cir") || + file.endsWith(".ckt") || + file.endsWith(".lib") || + file.endsWith(".sp")) { + files.append(getSubcircuitFile()+'/'+file); + } + } + + QString s; + for (const auto &file: files) { // for netlist + s += QStringLiteral(".INCLUDE \"%1\"\n").arg(file); + } + return s; +} diff --git a/qucs/components/libcomp.h b/qucs/components/libcomp.h index d14cd746c..db4f4a3c0 100644 --- a/qucs/components/libcomp.h +++ b/qucs/components/libcomp.h @@ -34,6 +34,7 @@ class LibComp : public MultiViewComponent { QString getSubcircuitFile(); QStringList getAttachedMOD(); // LibComp can reference cfunc.mod and ifspec.ifs QStringList getAttachedIFS(); // These should be compiled before SPICE simulation + QString getSpiceLibrary(); protected: QString netlist(); diff --git a/qucs/dialogs/librarydialog.cpp b/qucs/dialogs/librarydialog.cpp index 11a704840..654bae6fc 100644 --- a/qucs/dialogs/librarydialog.cpp +++ b/qucs/dialogs/librarydialog.cpp @@ -508,6 +508,17 @@ void LibraryDialog::slotSave() } kern->createSubNetlsit(ts,true); intoStream(Stream, tmp, "Spice"); + + QStringList libs = kern->collectSpiceLibraryFiles(Doc); + QStringList copiedFiles; + for (QString &file: libs) { + QString ofile = file; + intoFile(file, ofile, copiedFiles); + } + if (!copiedFiles.isEmpty()) { + Stream << "\n"; + } delete kern; QucsSettings.DefaultSimulator = sim; //} diff --git a/qucs/extsimkernels/abstractspicekernel.cpp b/qucs/extsimkernels/abstractspicekernel.cpp index 1fa21a169..f6e10955b 100644 --- a/qucs/extsimkernels/abstractspicekernel.cpp +++ b/qucs/extsimkernels/abstractspicekernel.cpp @@ -1595,3 +1595,30 @@ QString AbstractSpiceKernel::collectSpiceLibs(Schematic* sch) return collected_spicelib.join(""); } + +QStringList AbstractSpiceKernel::collectSpiceLibraryFiles(Schematic *sch) +{ + QStringList collected_spicelib; + for(Component *pc = sch->a_DocComps.first(); pc != 0; pc = sch->a_DocComps.next()) { + QStringList new_libs; + if (pc->Model == "Sub") { + Schematic *sub = new Schematic(nullptr, ((Subcircuit *)pc)->getSubcircuitFile()); + if(!sub->loadDocument()) // load document if possible + { + delete sub; + continue; + } + new_libs = collectSpiceLibraryFiles(sub); + delete sub; + } else { + new_libs = pc->getSpiceLibraryFiles(); + } + for (const auto&lib: new_libs) { + if (!collected_spicelib.contains(lib)) { + collected_spicelib.append(lib); + } + } + } + return collected_spicelib; +} + diff --git a/qucs/extsimkernels/abstractspicekernel.h b/qucs/extsimkernels/abstractspicekernel.h index d22572fbc..be8dbacfb 100644 --- a/qucs/extsimkernels/abstractspicekernel.h +++ b/qucs/extsimkernels/abstractspicekernel.h @@ -130,6 +130,7 @@ class AbstractSpiceKernel : public QObject virtual void SaveNetlist(QString filename); virtual bool waitEndOfSimulation(); void setConsole(QPlainTextEdit *console) { a_console = console; } + QStringList collectSpiceLibraryFiles(Schematic *sch); static QString collectSpiceLibs(Schematic* sch); signals: diff --git a/qucs/spicecomponents/sp_include.cpp b/qucs/spicecomponents/sp_include.cpp index c6725412c..f5ee916d2 100644 --- a/qucs/spicecomponents/sp_include.cpp +++ b/qucs/spicecomponents/sp_include.cpp @@ -99,3 +99,16 @@ QString S4Q_Include::getSpiceLibrary() return s; } +QStringList S4Q_Include::getSpiceLibraryFiles() +{ + QStringList files; + for (Property *pp : Props) { + QString val = pp->Value; + if (!val.isEmpty()) { + val = misc::properAbsFileName(val, containingSchematic); + files.append(val); + } + } + return files; +} + diff --git a/qucs/spicecomponents/sp_include.h b/qucs/spicecomponents/sp_include.h index e457cfda4..936ad2140 100644 --- a/qucs/spicecomponents/sp_include.h +++ b/qucs/spicecomponents/sp_include.h @@ -29,6 +29,7 @@ class S4Q_Include : public Component { Component* newOne(); static Element* info(QString&, char* &, bool getNewOne=false); QString getSpiceLibrary(); + QStringList getSpiceLibraryFiles(); protected: QString vhdlCode(int) { return QString(); } diff --git a/qucs/spicecomponents/spicelibcomp.cpp b/qucs/spicecomponents/spicelibcomp.cpp index 29a53f98f..c3d8a44ab 100644 --- a/qucs/spicecomponents/spicelibcomp.cpp +++ b/qucs/spicecomponents/spicelibcomp.cpp @@ -253,3 +253,11 @@ QString SpiceLibComp::getSpiceLibrary() QString s = QStringLiteral(".INCLUDE \"%1\"\n").arg(f); return s; } + +QStringList SpiceLibComp::getSpiceLibraryFiles() +{ + QString f = misc::properAbsFileName(getProperty("File")->Value, containingSchematic); + QStringList files; + files.append(f); + return files; +} diff --git a/qucs/spicecomponents/spicelibcomp.h b/qucs/spicecomponents/spicelibcomp.h index dc89997eb..ef65fb6b4 100644 --- a/qucs/spicecomponents/spicelibcomp.h +++ b/qucs/spicecomponents/spicelibcomp.h @@ -28,6 +28,7 @@ class SpiceLibComp : public MultiViewComponent { Component* newOne(); static Element* info(QString&, char* &, bool getNewOne=false); QString getSpiceLibrary(); + QStringList getSpiceLibraryFiles(); protected: QString spice_netlist(spicecompat::SpiceDialect dialect = spicecompat::SPICEDefault); From fcdcaeaebec56d58456cc182f0bd0e074e80c064 Mon Sep 17 00:00:00 2001 From: Vadim Kuznetsov Date: Sun, 19 Jan 2025 13:50:33 +0300 Subject: [PATCH 2/3] Add swtich to supress digital model generation when creating library --- qucs/components/libcomp.cpp | 8 ++++---- qucs/dialogs/librarydialog.cpp | 6 ++++++ qucs/dialogs/librarydialog.h | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/qucs/components/libcomp.cpp b/qucs/components/libcomp.cpp index e2f4fd933..955036cc3 100644 --- a/qucs/components/libcomp.cpp +++ b/qucs/components/libcomp.cpp @@ -424,10 +424,10 @@ QString LibComp::getSpiceLibrary() return QString(); } for (const auto &file : attach) { - if (file.endsWith(".cir") || - file.endsWith(".ckt") || - file.endsWith(".lib") || - file.endsWith(".sp")) { + if (file.endsWith(".cir", Qt::CaseInsensitive) || + file.endsWith(".ckt", Qt::CaseInsensitive) || + file.endsWith(".lib", Qt::CaseInsensitive) || + file.endsWith(".sp", Qt::CaseInsensitive)) { files.append(getSubcircuitFile()+'/'+file); } } diff --git a/qucs/dialogs/librarydialog.cpp b/qucs/dialogs/librarydialog.cpp index 654bae6fc..82eed8c7c 100644 --- a/qucs/dialogs/librarydialog.cpp +++ b/qucs/dialogs/librarydialog.cpp @@ -105,6 +105,10 @@ LibraryDialog::LibraryDialog(QWidget *parent) hCheck->addStretch(); connect(checkDescr, SIGNAL(stateChanged(int)), this, SLOT(slotCheckDescrChanged(int))); + checkAnalogLib = new QCheckBox(tr("Analog models only")); + checkAnalogLib->setChecked(true); + selectSubcktLayout->addWidget(checkAnalogLib); + // ........................................................... QGridLayout *gridButts = new QGridLayout(); selectSubcktLayout->addLayout(gridButts); @@ -523,6 +527,7 @@ void LibraryDialog::slotSave() QucsSettings.DefaultSimulator = sim; //} + if (!checkAnalogLib->isChecked()) { // save verilog model tmp.truncate(0); Doc->setIsVerilog(true); @@ -597,6 +602,7 @@ void LibraryDialog::slotSave() else { ErrText->insertPlainText("\n"); } + } Stream << " \n"; Doc->createSubcircuitSymbol(); diff --git a/qucs/dialogs/librarydialog.h b/qucs/dialogs/librarydialog.h index b76d615fe..4593ea773 100644 --- a/qucs/dialogs/librarydialog.h +++ b/qucs/dialogs/librarydialog.h @@ -94,6 +94,7 @@ private slots: QStringList SelectedNames; QStringList Descriptions; QCheckBox *checkDescr; + QCheckBox *checkAnalogLib; QFile LibFile; QDir LibDir; From 2261b6caf2f7c9aa4e03b6cc26a6fdd8a8cb470a Mon Sep 17 00:00:00 2001 From: Vadim Kuznetsov Date: Sun, 19 Jan 2025 14:29:45 +0300 Subject: [PATCH 3/3] Remove remains of XSPICE CM builder --- qucs/components/libcomp.cpp | 28 ------------ qucs/components/libcomp.h | 2 - qucs/mouseactions.cpp | 11 ----- qucs/qucs.cpp | 88 ------------------------------------- 4 files changed, 129 deletions(-) diff --git a/qucs/components/libcomp.cpp b/qucs/components/libcomp.cpp index 955036cc3..4e4931569 100644 --- a/qucs/components/libcomp.cpp +++ b/qucs/components/libcomp.cpp @@ -385,34 +385,6 @@ QString LibComp::cdl_netlist() return spice_netlist(spicecompat::CDL); } -QStringList LibComp::getAttachedIFS() -{ - QString content; - QStringList includes,attach,ifs_lst; - ifs_lst.clear(); - - int r = loadSection("Spice",content,&includes,&attach); - if (r<0) return ifs_lst; - for (const QString& file : attach) { - if (file.endsWith(".ifs")) ifs_lst.append(getSubcircuitFile()+'/'+file); - } - return ifs_lst; -} - -QStringList LibComp::getAttachedMOD() -{ - QString content; - QStringList includes,attach,mod_lst; - mod_lst.clear(); - - int r = loadSection("Spice",content,&includes,&attach); - if (r<0) return mod_lst; - for (const QString& file : attach) { - if (file.endsWith(".mod")) mod_lst.append(getSubcircuitFile()+'/'+file); - } - return mod_lst; -} - QString LibComp::getSpiceLibrary() { QStringList files; diff --git a/qucs/components/libcomp.h b/qucs/components/libcomp.h index db4f4a3c0..024de77ce 100644 --- a/qucs/components/libcomp.h +++ b/qucs/components/libcomp.h @@ -32,8 +32,6 @@ class LibComp : public MultiViewComponent { bool createSubNetlist(QTextStream *, QStringList&, int type=1); QString getSubcircuitFile(); - QStringList getAttachedMOD(); // LibComp can reference cfunc.mod and ifspec.ifs - QStringList getAttachedIFS(); // These should be compiled before SPICE simulation QString getSpiceLibrary(); protected: diff --git a/qucs/mouseactions.cpp b/qucs/mouseactions.cpp index 57441383d..f0ecea6b8 100644 --- a/qucs/mouseactions.cpp +++ b/qucs/mouseactions.cpp @@ -918,17 +918,6 @@ void MouseActions::rightPressMenu(Schematic *Doc, QMouseEvent *Event, float fX, SLOT(slotSaveDiagramToGraphicsFile())); ComponentMenu->addAction(actExport); } - /*if (focusElement->Type & isComponent) { - Component *pc = (Component *)focusElement; - if (pc->Model == "EDD") { - QAction *actEDDtoIFS = new QAction(QObject::tr("Create XSPICE IFS"), QucsMain); - QObject::connect(actEDDtoIFS,SIGNAL(triggered(bool)),QucsMain,SLOT(slotEDDtoIFS())); - ComponentMenu->addAction(actEDDtoIFS); - QAction *actEDDtoMOD = new QAction(QObject::tr("Create XSPICE MOD"), QucsMain); - QObject::connect(actEDDtoMOD,SIGNAL(triggered(bool)),QucsMain,SLOT(slotEDDtoMOD())); - ComponentMenu->addAction(actEDDtoMOD); - } - }*/ } break; } diff --git a/qucs/qucs.cpp b/qucs/qucs.cpp index 3056274ea..232898035 100644 --- a/qucs/qucs.cpp +++ b/qucs/qucs.cpp @@ -3645,94 +3645,6 @@ void QucsApp::slotBuildVAModule() } - -/*void QucsApp::slotBuildXSPICEIfs(int mode) -{ - if (!isTextDocument(DocumentTab->currentWidget())) { - Schematic *Sch = (Schematic*)DocumentTab->currentWidget(); - - QFileInfo inf(Sch->getDocName()); - - QString msg,ext; - switch(mode) { - case spicecompat::cmgenSUBifs: - case spicecompat::cmgenEDDifs: msg = inf.path()+QDir::separator()+inf.baseName()+".ifs"; - ext = "XSPICE IFS (*.ifs)"; - break; - case spicecompat::cmgenSUBmod: - case spicecompat::cmgenEDDmod: msg = inf.path()+QDir::separator()+inf.baseName()+".mod"; - ext = "XSPICE MOD (*.mod)"; - break; - default: break; - } - - QString filename = QFileDialog::getSaveFileName(this,tr("Save XSPICE source"),msg,ext); - if (filename.isEmpty()) return; - - QFile f(filename); - if (f.open(QIODevice::WriteOnly)) { - QTextStream stream(&f); - CodeModelGen *cmgen = new CodeModelGen; - bool r = false; - switch(mode) { - case spicecompat::cmgenSUBifs: r = cmgen->createIFS(stream,Sch); - case spicecompat::cmgenEDDifs: { - for(Component *pc = Sch->a_DocComps.first(); pc != 0; pc = Sch->a_DocComps.next()) { - if (pc->isSelected) { - r = cmgen->createIFSfromEDD(stream,Sch,pc); - break; - } - } - } - break; - case spicecompat::cmgenEDDmod : { - for(Component *pc = Sch->a_DocComps.first(); pc != 0; pc = Sch->a_DocComps.next()) { - if (pc->isSelected) { - r = cmgen->createMODfromEDD(stream,Sch,pc); - break; - } - } - } - break; - default: r = false; - break; - } - QString errs; - if (!r) errs = tr("Create XSPICE CodeModel" - "Create CodeModel source file failed!" - "Schematic is not subciruit!"); - - messageDock->reset(); - messageDock->msgDock->setWindowTitle(tr("Debug messages dock")); - messageDock->builderTabs->setTabIcon(0,QPixmap()); - messageDock->builderTabs->setTabText(0,tr("XSPICE")); - messageDock->builderTabs->setTabIcon(1,QPixmap()); - messageDock->admsOutput-> - insertPlainText(QStringLiteral("Creating XSPICE source file: %1\n").arg(filename)); - errs += cmgen->getLog(); - if (errs.isEmpty()) { - messageDock->admsOutput->insertPlainText(tr("Success!\n")); - } else { - messageDock->admsOutput->insertPlainText(errs); - } - messageDock->msgDock->show(); - delete cmgen; - f.close(); - } - } -} - - -void QucsApp::slotEDDtoIFS() -{ - slotBuildXSPICEIfs(spicecompat::cmgenEDDifs); -} - -void QucsApp::slotEDDtoMOD() -{ - slotBuildXSPICEIfs(spicecompat::cmgenEDDmod); -}*/ - void QucsApp::slotShowModel() { DisplayDialog *dlg = new DisplayDialog(this,Symbol->ModelString,