diff --git a/plugins/simulator/netlist_simulator_controller/include/netlist_simulator_controller/netlist_simulator_controller.h b/plugins/simulator/netlist_simulator_controller/include/netlist_simulator_controller/netlist_simulator_controller.h index 65a0bed184d..59267fe863b 100644 --- a/plugins/simulator/netlist_simulator_controller/include/netlist_simulator_controller/netlist_simulator_controller.h +++ b/plugins/simulator/netlist_simulator_controller/include/netlist_simulator_controller/netlist_simulator_controller.h @@ -136,6 +136,13 @@ class NETLIST_API NetlistSimulatorController : public QObject { */ u32 add_waveform_group(const PinGroup* pin_group); + /** + * Create a waveform group from the nets of a given gate pin group. + * + * @param pin_group The pin_group to create waveform group from. + * @return ID of new waveform group + */ + u32 add_waveform_group(const Gate* gate, const PinGroup* pin_group); /** * Create a waveform group from the nets of a given module pin group. diff --git a/plugins/simulator/netlist_simulator_controller/include/netlist_simulator_controller/simulation_input.h b/plugins/simulator/netlist_simulator_controller/include/netlist_simulator_controller/simulation_input.h index a2f43268c99..3c10a89cba0 100644 --- a/plugins/simulator/netlist_simulator_controller/include/netlist_simulator_controller/simulation_input.h +++ b/plugins/simulator/netlist_simulator_controller/include/netlist_simulator_controller/simulation_input.h @@ -30,6 +30,9 @@ #include #include "hal_core/defines.h" #include "hal_core/netlist/boolean_function.h" +#include "hal_core/netlist/pins/module_pin.h" +#include "hal_core/netlist/pins/gate_pin.h" +#include "hal_core/netlist/pins/pin_group.h" namespace hal { class Gate; @@ -56,10 +59,11 @@ namespace hal { struct NetGroup { - std::string name; - std::vector > nets; - - NetGroup(const std::string& nam) : name(nam) {;} + bool is_input; + const Gate* gate; + PinGroup* module_pin_group; + PinGroup* gate_pin_group; + NetGroup() : is_input(true), gate(nullptr), module_pin_group(nullptr), gate_pin_group(nullptr) {;} }; private: @@ -76,7 +80,6 @@ namespace hal { void compute_input_nets(); void compute_output_nets(); void compute_partial_nets(); - void compute_net_groups(); public: SimulationInput() : mNoClockUsed(false) {;} @@ -176,5 +179,9 @@ namespace hal { * @param filename name of file to be created */ void dump(std::string filename = std::string()) const; + + void compute_net_groups(); + + const std::vector& get_net_groups() const { return m_netgroups; } }; } diff --git a/plugins/simulator/netlist_simulator_controller/python/python_bindings.cpp b/plugins/simulator/netlist_simulator_controller/python/python_bindings.cpp index 15a4652c9b1..7289a4d5daa 100644 --- a/plugins/simulator/netlist_simulator_controller/python/python_bindings.cpp +++ b/plugins/simulator/netlist_simulator_controller/python/python_bindings.cpp @@ -155,11 +155,20 @@ namespace hal )") .def("add_waveform_group", py::overload_cast*>(&NetlistSimulatorController::add_waveform_group), py::arg("pin_group"), R"( - Create a waveform group from the nets of a given module pin group. + Create a waveform group from the nets of a given module pin group. - :param hal_py.ModulePinGroup pin_group: The pin_group to create waveform group from. - :return: ID of the new waveform group. - :rtype: int + :param hal_py.ModulePinGroup pin_group: The pin_group to create waveform group from. + :return: ID of the new waveform group. + :rtype: int + )") + + .def("add_waveform_group", py::overload_cast*>(&NetlistSimulatorController::add_waveform_group), py::arg("gate"), py::arg("pin_group"), R"( + Create a waveform group from the nets of a given gate pin group. + + :param hal_py.Gate: The gate instance the pin_group belongs to. + :param hal_py.GatePinGroup pin_group: The pin_group to create waveform group from. + :return: ID of the new waveform group. + :rtype: int )") .def("add_waveform_group", py::overload_cast*>(&NetlistSimulatorController::add_waveform_group), py::arg("name"), py::arg("pin_group"), R"( diff --git a/plugins/simulator/netlist_simulator_controller/src/netlist_simulator_controller.cpp b/plugins/simulator/netlist_simulator_controller/src/netlist_simulator_controller.cpp index 7f0ccfe5051..e0c3d43d64e 100644 --- a/plugins/simulator/netlist_simulator_controller/src/netlist_simulator_controller.cpp +++ b/plugins/simulator/netlist_simulator_controller/src/netlist_simulator_controller.cpp @@ -6,6 +6,7 @@ #include "hal_core/netlist/project_manager.h" #include "hal_core/utilities/json_write_document.h" #include "hal_core/utilities/log.h" +#include "hal_core/netlist/gate_library/enums/pin_direction.h" #include "netlist_simulator_controller/plugin_netlist_simulator_controller.h" #include "netlist_simulator_controller/saleae_directory.h" #include "netlist_simulator_controller/saleae_parser.h" @@ -335,6 +336,30 @@ namespace hal return add_waveform_group(pin_group->get_name(), nets); } + u32 NetlistSimulatorController::add_waveform_group(const Gate *gate, const PinGroup* pin_group) + { + std::vector nets; + for (const auto pin : pin_group->get_pins()) + { + Net* n = nullptr; + switch (pin->get_direction()) + { + case PinDirection::input: + n = gate->get_fan_in_net(pin); + break; + case PinDirection::output: + n = gate->get_fan_out_net(pin); + break; + default: + break; + } + + if (n) nets.push_back(n); + } + + return add_waveform_group(pin_group->get_name(), nets); + } + u32 NetlistSimulatorController::add_waveform_group(const std::string& name, const PinGroup* pin_group) { std::vector nets; @@ -880,30 +905,15 @@ namespace hal void NetlistSimulatorController::make_waveform_groups() { - std::unordered_map> containedModules; - for (const Gate* g: mSimulationInput->get_gates()) - { - Module* m = g->get_module(); - // test all parent modules whether gates are contained in simulation - while (m) - { - auto it = containedModules.find(m); - if (it == containedModules.end()) - { - std::vector gats = m->get_gates(nullptr,true); - containedModules.insert(std::make_pair(m,std::unordered_set(gats.begin(),gats.end()))); - it = containedModules.find(m); - } - auto jt = it->second.find(g); - if (jt!=it->second.end()) - it->second.erase(jt); - m = m->get_parent_module(); - } - } - for (const auto &it : containedModules) + mSimulationInput->compute_net_groups(); + + for (const SimulationInput::NetGroup& ng : mSimulationInput->get_net_groups()) { - if (it.second.empty()) - std::cerr << it.first->get_id() << " mod simulated <" << it.first->get_name() << ">" << std::endl; + if (!ng.is_input) continue; + if (ng.gate) + add_waveform_group(ng.gate, ng.gate_pin_group); + else + add_waveform_group(ng.module_pin_group); } } diff --git a/plugins/simulator/netlist_simulator_controller/src/simulation_input.cpp b/plugins/simulator/netlist_simulator_controller/src/simulation_input.cpp index 9556d607732..52b8e7a0f96 100644 --- a/plugins/simulator/netlist_simulator_controller/src/simulation_input.cpp +++ b/plugins/simulator/netlist_simulator_controller/src/simulation_input.cpp @@ -1,4 +1,4 @@ -#include "netlist_simulator_controller/simulation_input.h" +#include "netlist_simulator_controller/simulation_input.h" #include "hal_core/netlist/gate.h" #include "hal_core/netlist/net.h" #include "hal_core/utilities/log.h" @@ -19,7 +19,6 @@ namespace hal { compute_input_nets(); compute_output_nets(); compute_partial_nets(); - compute_net_groups(); } const std::unordered_set& SimulationInput::get_gates() const @@ -247,14 +246,12 @@ namespace hal { { if (pg->size() < 2) continue; bool pin_group_simulated = true; - NetGroup group(pg->get_name()); for (ModulePin* mp : pg->get_pins()) { Net* n = mp->get_net(); if (n) { - group.nets.push_back(std::make_pair(mp->get_group().second,n)); if (single_nets.find(n) == single_nets.end()) { // pin : net exists and is not part of the simulation, ignore pin group @@ -265,8 +262,19 @@ namespace hal { } if (pin_group_simulated) { - m_netgroups.push_back(group); - for (auto pair : group.nets) single_nets.erase(pair.second); + NetGroup group; + group.module_pin_group = pg; + for (ModulePin* mp : pg->get_pins()) + { + Net* n = mp->get_net(); + if (n) + { + single_nets.erase(n); + if (!is_input_net(n)) + group.is_input = false; + } + } + m_netgroups.push_back(group); } } @@ -282,12 +290,11 @@ namespace hal { { if (pg->size() < 2) continue; bool pin_group_simulated = true; - NetGroup group(pg->get_name()); for (GatePin* gp : pg->get_pins()) { Net* n = nullptr; - switch (pg->get_direction()) + switch (gp->get_direction()) { case PinDirection::inout: n = g->get_fan_in_net(gp); @@ -300,7 +307,6 @@ namespace hal { } if (n) { - group.nets.push_back(std::make_pair(gp->get_group().second,n)); if (single_nets.find(n) == single_nets.end()) { // pin : net alreade assigned to module pin group, ignore gate pin group @@ -312,8 +318,24 @@ namespace hal { if (pin_group_simulated) { + NetGroup group; + group.gate = g; + group.gate_pin_group = pg; + if (pg->get_direction() == PinDirection::input) + { + for (GatePin* gp : pg->get_pins()) + { + Net* n = g->get_fan_in_net(gp); + if (n && !is_input_net(n)) + { + group.is_input = false; + break; + } + } + } + else + group.is_input = false; m_netgroups.push_back(group); - for (auto pair : group.nets) single_nets.erase(pair.second); } } } diff --git a/plugins/simulator/waveform_viewer/src/waveform_viewer.cpp b/plugins/simulator/waveform_viewer/src/waveform_viewer.cpp index e69de29bb2d..5fb954a8d32 100644 --- a/plugins/simulator/waveform_viewer/src/waveform_viewer.cpp +++ b/plugins/simulator/waveform_viewer/src/waveform_viewer.cpp @@ -0,0 +1,512 @@ +#include "waveform_viewer/waveform_viewer.h" + +#include "waveform_viewer/wave_widget.h" +#include "waveform_viewer/simulation_setting_dialog.h" +#include "netlist_simulator_controller/simulation_process.h" +#include "netlist_simulator_controller/plugin_netlist_simulator_controller.h" +#include "netlist_simulator_controller/simulation_engine.h" + +#include "waveform_viewer/wizard.h" + +#include "netlist_simulator_controller/plugin_netlist_simulator_controller.h" +#include "waveform_viewer/gate_selection_dialog.h" +#include "waveform_viewer/clock_set_dialog.h" +#include "waveform_viewer/wave_graphics_canvas.h" +#include "hal_core/netlist/gate.h" +#include "hal_core/netlist/net.h" +#include "hal_core/netlist/netlist.h" +#include "hal_core/utilities/log.h" +#include "hal_core/plugin_system/plugin_manager.h" +#include "gui/gui_globals.h" +#include "gui/gui_utils/graphics.h" +#include "gui/toolbar/toolbar.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hal_core/plugin_system/plugin_manager.h" + +namespace hal +{ + + ExternalContentWidget* WaveformViewerFactory::contentFactory() const + { + return new WaveformViewer; + } + + void WaveformViewer::restoreFromProject() + { + NetlistSimulatorControllerPlugin* ctrlPlug = static_cast(plugin_manager::get_plugin_instance("netlist_simulator_controller")); + if (!ctrlPlug || !ctrlPlug->sSimulatorSerializer) + { + return; + } + for (std::unique_ptr& ctrlRef : ctrlPlug->sSimulatorSerializer->restore()) + { + if (!ctrlRef) continue; + takeControllerOwnership(ctrlRef, false); // already created by restore() + } + } + + WaveformViewer::WaveformViewer(QWidget *parent) + : ExternalContentWidget("waveform_viewer","WaveformViewer",parent), + mVisualizeNetState(false), mOwnershipRequired(false), mCurrentWaveWidget(nullptr) + { + LogManager::get_instance()->add_channel(std::string("waveform_viewer"), {LogManager::create_stdout_sink(), LogManager::create_file_sink(), LogManager::create_gui_sink()}, "info"); + mCreateControlAction = new QAction(this); + mSimulSettingsAction = new QAction(this); + mOpenInputfileAction = new QAction(this); + mSaveWaveformsAction = new QAction(this); + mInvokeSWizardAction = new QAction(this); + mAddResultWaveAction = new QAction(this); + mToggleMaxZoomAction = new QAction(this); + mUndoZoomShiftAction = new QAction(this); + + mCreateControlAction->setIcon(gui_utility::getStyledSvgIcon("all->#FFFFFF",":/icons/plus")); + mAddResultWaveAction->setIcon(QIcon(":/icons/add_waveform")); + mToggleMaxZoomAction->setIcon(QIcon(":/icons/zoom_waveform")); + mUndoZoomShiftAction->setIcon(gui_utility::getStyledSvgIcon("all->#FFFFFF",":/icons/undo2")); + + mCreateControlAction->setToolTip("Create simulation controller"); + mSimulSettingsAction->setToolTip("Simulation settings"); + mOpenInputfileAction->setToolTip("Open input file"); + mSaveWaveformsAction->setToolTip("Save waveform data to file"); + mInvokeSWizardAction->setToolTip("Invoke simulation wizard"); + mAddResultWaveAction->setToolTip("Add waveform net"); + mToggleMaxZoomAction->setToolTip("Toggle max/min zoom"); + mUndoZoomShiftAction->setToolTip("Undo last zoom or horizontal scroll"); + + connect(mCreateControlAction, &QAction::triggered, this, &WaveformViewer::handleCreateControl); + connect(mSimulSettingsAction, &QAction::triggered, this, &WaveformViewer::handleSimulSettings); + connect(mOpenInputfileAction, &QAction::triggered, this, &WaveformViewer::handleOpenInputFile); + connect(mSaveWaveformsAction, &QAction::triggered, this, &WaveformViewer::handleSaveWaveforms); + connect(mInvokeSWizardAction, &QAction::triggered, this, &WaveformViewer::handleInvokeWizzard); + connect(mAddResultWaveAction, &QAction::triggered, this, &WaveformViewer::handleAddResultWave); + connect(mToggleMaxZoomAction, &QAction::triggered, this, &WaveformViewer::handleToggleMaxZoom); + connect(mUndoZoomShiftAction, &QAction::triggered, this, &WaveformViewer::handleUndoZoomShift); + + mTabWidget = new QTabWidget(this); + mTabWidget->setTabsClosable(true); + mTabWidget->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); + connect(mTabWidget,&QTabWidget::tabCloseRequested,this,&WaveformViewer::handleTabClosed); + connect(mTabWidget,&QTabWidget::currentChanged,this,&WaveformViewer::currentTabChanged); + mContentLayout->addWidget(mTabWidget); + mStatusBar = new QStatusBar(this); + mProgress = new QProgressBar(mStatusBar); + mProgress->setFormat("Import waveform data : %p%"); + mProgress->setTextVisible(true); + mProgress->setRange(0,100); + mStatusBar->addWidget(mProgress,100); + mProgress->hide(); + mStatusBar->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred); + mContentLayout->addWidget(mStatusBar); + if (gSelectionRelay) + connect(gSelectionRelay,&SelectionRelay::selectionChanged,this,&WaveformViewer::handleSelectionChanged); + + NetlistSimulatorControllerMap* nscm = NetlistSimulatorControllerMap::instance(); + connect(nscm, &NetlistSimulatorControllerMap::controllerAdded, + this, &WaveformViewer::handleControllerAdded, Qt::QueuedConnection); + connect(nscm, &NetlistSimulatorControllerMap::controllerRemoved, + this, &WaveformViewer::handleControllerRemoved, Qt::QueuedConnection); + currentStateChanged(NetlistSimulatorController::NoGatesSelected); + } + + WaveformViewer::~WaveformViewer() + { + closeEvent(nullptr); + } + + void WaveformViewer::closeEvent(QCloseEvent*event) + { + Q_UNUSED(event); + NetlistSimulatorControllerMap* nscm = NetlistSimulatorControllerMap::instance(); + disconnect(nscm, &NetlistSimulatorControllerMap::controllerAdded, this, &WaveformViewer::handleControllerAdded); + disconnect(nscm, &NetlistSimulatorControllerMap::controllerRemoved, this, &WaveformViewer::handleControllerRemoved); + } + + void WaveformViewer::showProgress(int percent) + { + if (percent < 0) + { + mProgress->setValue(0); + mProgress->hide(); + currentStateChanged(mCurrentWaveWidget->state()); + } + else if (percent != mProgress->value()) + { + mStatusBar->clearMessage(); + mProgress->show(); + mProgress->setValue(percent); + } + } + + void WaveformViewer::currentTabChanged(int inx) + { + if (inx >= 0 && mCurrentWaveWidget == mTabWidget->widget(inx)) return; + if (mCurrentWaveWidget) + disconnect(mCurrentWaveWidget,&WaveWidget::stateChanged,this,&WaveformViewer::currentStateChanged); + if (inx < 0) + { + mCurrentWaveWidget = nullptr; + currentStateChanged(NetlistSimulatorController::NoGatesSelected); + return; + } + mCurrentWaveWidget = static_cast(mTabWidget->widget(inx)); + currentStateChanged(mCurrentWaveWidget->state()); + connect(mCurrentWaveWidget,&WaveWidget::stateChanged,this,&WaveformViewer::currentStateChanged); + } + + void WaveformViewer::handleParseComplete() + { + if (!mCurrentWaveWidget) return; + mAddResultWaveAction->setEnabled(mCurrentWaveWidget->canImportWires()); + } + + void WaveformViewer::testUndoEnable() + { + if (!mCurrentWaveWidget) + mUndoZoomShiftAction->setDisabled(true); + else + mUndoZoomShiftAction->setEnabled(mCurrentWaveWidget->graphicCanvas()->canUndoZoom()); + mUndoZoomShiftAction->setIcon(gui_utility::getStyledSvgIcon(mUndoZoomShiftAction->isEnabled() ? "all->#FFFFFF" : "all->#808080",":/icons/undo2")); + } + + void WaveformViewer::currentStateChanged(NetlistSimulatorController::SimulationState state) + { + mOpenInputfileAction->setEnabled(true); + mInvokeSWizardAction->setEnabled(true); + mOpenInputfileAction->setIcon(gui_utility::getStyledSvgIcon("all->#3192C5",":/icons/folder")); + if (!mCurrentWaveWidget || state == NetlistSimulatorController::SimulationRun || mProgress->isVisible()) + { + mSimulSettingsAction->setDisabled(true); + mSaveWaveformsAction->setDisabled(true); + + // TODO: das ganze muss anders gestartet werden sonst fehlen einpar ptr + mInvokeSWizardAction->setDisabled(true); + mAddResultWaveAction->setDisabled(true); + mToggleMaxZoomAction->setDisabled(true); + } + else + + { + mSimulSettingsAction->setEnabled(true); + mSaveWaveformsAction->setEnabled(state != NetlistSimulatorController::NoGatesSelected); + + //mInvokeSWizardAction->setEnabled(state == NetlistSimulatorController::ParameterReady); + mToggleMaxZoomAction->setEnabled(!mCurrentWaveWidget->isEmpty()); + } + mSimulSettingsAction->setIcon(gui_utility::getStyledSvgIcon(mSimulSettingsAction->isEnabled() ? "all->#FFFFFF" : "all->#808080",":/icons/preferences")); + + mSaveWaveformsAction->setIcon(gui_utility::getStyledSvgIcon(mSaveWaveformsAction->isEnabled() ? "all->#3192C5" : "all->#808080",":/icons/save")); + mInvokeSWizardAction->setIcon(gui_utility::getStyledSvgIcon(mInvokeSWizardAction->isEnabled() ? "all->#20FF80" : "all->#808080",":/icons/run")); + testUndoEnable(); + + if (!mCurrentWaveWidget) + displayStatusMessage(); + else + { + mAddResultWaveAction->setEnabled(mCurrentWaveWidget->canImportWires()); + switch (state) { + case NetlistSimulatorController::NoGatesSelected: displayStatusMessage("Select gates to create (partial) netlist for simulation"); break; + case NetlistSimulatorController::ParameterSetup: displayStatusMessage("Setup parameter for simulation"); break; + case NetlistSimulatorController::ParameterReady: displayStatusMessage("Continue parameter setup or start simulation"); break; + case NetlistSimulatorController::SimulationRun: displayStatusMessage("Simulation engine running, please wait ..."); break; + case NetlistSimulatorController::ShowResults: displayStatusMessage("Simulation successful, add waveform data to visualize results"); break; + case NetlistSimulatorController::EngineFailed: displayStatusMessage("Simulation engine failed"); break; + } + } + } + + void WaveformViewer::displayStatusMessage(const QString& msg) + { + if (msg.isEmpty()) + { + mStatusBar->showMessage("Create new simulation controller"); + } + else + mStatusBar->showMessage(msg); + } + + void WaveformViewer::setupToolbar(Toolbar* toolbar) + { + toolbar->addAction(mCreateControlAction); + toolbar->addAction(mInvokeSWizardAction); + toolbar->addAction(mSimulSettingsAction); + toolbar->addAction(mOpenInputfileAction); + toolbar->addAction(mSaveWaveformsAction); + toolbar->addAction(mAddResultWaveAction); + toolbar->addAction(mToggleMaxZoomAction); + toolbar->addAction(mUndoZoomShiftAction); + } + + void WaveformViewer::handleTabClosed(int inx) + { + WaveWidget* ww = static_cast(mTabWidget->widget(inx)); + if (!ww->triggerClose()) + log_warning(ww->controller()->get_name(), "Cannot close tab for externally owned controller."); + } + + void WaveformViewer::handleCreateControl() + { + NetlistSimulatorControllerPlugin* ctrlPlug = static_cast(plugin_manager::get_plugin_instance("netlist_simulator_controller")); + if (!ctrlPlug) + { + log_warning("waveform_viewer", "Plugin 'netlist_simulator_controller' not found"); + return; + } + std::unique_ptr ctrlRef = ctrlPlug->create_simulator_controller(); + if (ctrlRef) + takeControllerOwnership(ctrlRef, false); + } + + void WaveformViewer::handleSimulSettings() + { + QMenu* settingMenu = new QMenu(this); + QAction* act; + + act = new QAction("Show output of engine"); + connect(act, &QAction::triggered, this, &WaveformViewer::handleShowEngineOutput); + settingMenu->addAction(act); + + settingMenu->addSeparator(); + act = new QAction("Refresh net names", settingMenu); + connect(act, &QAction::triggered, this, &WaveformViewer::handleRefreshNetNames); + settingMenu->addAction(act); + + act = new QAction("Visualize net state by color", settingMenu); + act->setCheckable(true); + act->setChecked(mVisualizeNetState); + connect (act, &QAction::triggered, this, &WaveformViewer::setVisualizeNetState); + settingMenu->addAction(act); + + act = new QAction("Settings ..."); + connect(act, &QAction::triggered, this, &WaveformViewer::handleOpenSettingsDialog); + settingMenu->addAction(act); + + settingMenu->exec(mapToGlobal(QPoint(10,3))); + } + + void WaveformViewer::handleOpenSettingsDialog() + { + SimulationSettingDialog ssd(NetlistSimulatorControllerPlugin::sSimulationSettings,this); + ssd.exec(); + } + + void WaveformViewer::handleShowEngineOutput() + { + if (!mCurrentWaveWidget) return; + QString fname = QDir(QString::fromStdString(mCurrentWaveWidget->controller()->get_working_directory())).absoluteFilePath(SimulationProcessLog::sLogFilename); + QFile log(fname); + if (!log.open(QIODevice::ReadOnly)) return; + QTextEdit* browser = new QTextEdit; + browser->setReadOnly(true); + browser->setHtml(QString::fromUtf8(log.readAll())); + QSize scrSize = QGuiApplication::primaryScreen()->size(); + browser->setGeometry(scrSize.width()/10,scrSize.height()/10,scrSize.width()*4/5,scrSize.height()*4/5); + browser->setWindowTitle("Simulation engine log <" + fname + ">"); + browser->show(); + } + + void WaveformViewer::handleRefreshNetNames() + { + for (int inx=0; inxcount(); inx++) + { + WaveWidget* ww = static_cast(mTabWidget->widget(inx)); + ww->refreshNetNames(); + } + } + + void WaveformViewer::setVisualizeNetState(bool state) + { + if (state == mVisualizeNetState) return; + mVisualizeNetState = state; + for (int inx=0; inx < mTabWidget->count(); inx++) + { + WaveWidget* ww = static_cast(mTabWidget->widget(inx)); + ww->setVisualizeNetState(mVisualizeNetState, inx==mTabWidget->currentIndex()); + } + } + + void WaveformViewer::handleControllerAdded(u32 controllerId) + { + // nothing to do here, viewer will open widget when taking over ownership + if (mOwnershipRequired) return; + + // check whether controller already added + for (int inx=0; inxcount(); inx++) + { + WaveWidget* ww = static_cast(mTabWidget->widget(inx)); + if (controllerId == ww->controllerId()) return; + } + NetlistSimulatorController* nsc = NetlistSimulatorControllerMap::instance()->controller(controllerId); + if (!nsc) return; + WaveWidget* ww = new WaveWidget(nsc, mTabWidget); + mTabWidget->addTab(ww,nsc->name()); + showCloseButton(); + } + + void WaveformViewer::handleControllerRemoved(u32 controllerId) + { + for (int inx=0; inxcount(); inx++) + { + WaveWidget* ww = static_cast(mTabWidget->widget(inx)); + if (ww->controllerId() == controllerId) + { + mTabWidget->removeTab(inx); + ww->deleteLater(); + } + } + } + + void WaveformViewer::handleOpenInputFile() + { + QString filter = QString("Saved data (%1)").arg(NetlistSimulatorController::sPersistFile); + if (mCurrentWaveWidget) + filter += ";; VCD files (*.vcd);; CSV files (*.csv)"; + + QString filename = + QFileDialog::getOpenFileName(this, "Load input wave file", ".", filter); + if (filename.isEmpty()) return; + if (filename.endsWith(NetlistSimulatorController::sPersistFile)) + { + NetlistSimulatorControllerPlugin* ctrlPlug = static_cast(plugin_manager::get_plugin_instance("netlist_simulator_controller")); + if (ctrlPlug) + { + mOwnershipRequired = true; + std::unique_ptr ctrlRef = ctrlPlug->restore_simulator_controller(gNetlist,filename.toStdString()); + takeControllerOwnership(ctrlRef, true); + mOwnershipRequired = false; + } + } + else if (mCurrentWaveWidget && mCurrentWaveWidget->controller()->can_import_data() && filename.toLower().endsWith(".vcd")) + mCurrentWaveWidget->controller()->import_vcd(filename.toStdString(),NetlistSimulatorController::GlobalInputs); + else if (mCurrentWaveWidget && mCurrentWaveWidget->controller()->can_import_data() && filename.toLower().endsWith(".csv")) + mCurrentWaveWidget->controller()->import_csv(filename.toStdString(),NetlistSimulatorController::GlobalInputs); + else if (mCurrentWaveWidget) + log_warning(mCurrentWaveWidget->controller()->get_name(), "Cannot parse file '{}' (unknown extension ore wrong state).", filename.toStdString()); + else + log_warning("simulation_plugin", "Unable to restore saved data from file '{}'.", filename.toStdString()); + } + + void WaveformViewer::showCloseButton() + { + for (int i=0; icount(); i++) + { + bool own = static_cast(mTabWidget->widget(i))->hasOwnership(); + for (int j=0; j<2; j++) + { + QWidget* closeBut = mTabWidget->tabBar()->tabButton(i,j?QTabBar::LeftSide:QTabBar::RightSide); + if (closeBut && closeBut->metaObject()->className() == QByteArray("CloseButton")) + { + if (own) + { + if (!closeBut->isVisible()) + closeBut->show(); + } + else + { + if (closeBut->isVisible()) + closeBut->hide(); + } + } + } + } + } + + void WaveformViewer::takeControllerOwnership(std::unique_ptr &ctrlRef, bool create) + { + NetlistSimulatorController* nsc = ctrlRef.get(); + + WaveWidget* ww = nullptr; + if (create) + { + ww = new WaveWidget(nsc, mTabWidget); + mTabWidget->addTab(ww,nsc->name()); + } + else + { + for (int inx=0; inxcount(); inx++) + { + WaveWidget* wwTest = static_cast(mTabWidget->widget(inx)); + if (ctrlRef.get()->get_id() == wwTest->controllerId()) + { + ww = wwTest; + break; + } + } + + } + Q_ASSERT(ww); + ww->takeOwnership(ctrlRef); + showCloseButton(); + } + + void WaveformViewer::handleSaveWaveforms() + { + if (!mCurrentWaveWidget) return; + + QString filename = + QFileDialog::getSaveFileName(this, "Save waveform data to file", ".", ("VCD Files (*.vcd)") ); + if (filename.isEmpty()) return; + mCurrentWaveWidget->controller()->generate_vcd(filename.toStdString()); + } + + void WaveformViewer::handleInvokeWizzard() + { + if (!mCurrentWaveWidget) return; + Wizard wizard(NetlistSimulatorControllerPlugin::sSimulationSettings, mCurrentWaveWidget->controller(), mCurrentWaveWidget); + wizard.exec(); + } + + void WaveformViewer::handleToggleMaxZoom() + { + if (!mCurrentWaveWidget) return; + mCurrentWaveWidget->graphicCanvas()->toggleZoom(); + } + + void WaveformViewer::handleUndoZoomShift() + { + if (!mCurrentWaveWidget) return; + mCurrentWaveWidget->graphicCanvas()->undoZoom(); + } + + void WaveformViewer::handleAddResultWave() + { + if (!mCurrentWaveWidget) return; + mCurrentWaveWidget->addResults(); + mAddResultWaveAction->setEnabled(mCurrentWaveWidget->canImportWires()); + } + + void WaveformViewer::setGates(std::vector gates) + { + if (!mCurrentWaveWidget) return; + mCurrentWaveWidget->setGates(gates); + } + + void WaveformViewer::handleSelectionChanged(void* sender) + { + Q_UNUSED(sender); + /* + for (u32 nid : gSelectionRelay->selectedNetsList()) + { + Net* n = gNetlist->get_net_by_id(nid); + if (!n) continue; + const WaveData* wd = mResultMap.value(n->get_id()); + if (!wd) continue; + WaveData* wdCopy = new WaveData(*wd); +// TODO mWaveWidget->addOrReplaceWave(wdCopy); + } + */ + } +} // namespace hal