From 2851122020d776d21ef3e09354a5ca50d947b8ca Mon Sep 17 00:00:00 2001 From: Ole Engelbrecht Date: Mon, 22 Jul 2024 20:32:56 +0200 Subject: [PATCH] cleanup and fixed a few bugs like keep same position etc. --- .../netlist_modifier/ini_settings_popup.h | 25 +- .../netlist_modifier/netlist_modifier.h | 9 +- .../netlist_modifier/src/encrypted_zip.cpp | 110 +++-- .../src/modify_gatelibrary.cpp | 24 +- .../netlist_modifier/src/modify_in_place.cpp | 48 ++- .../netlist_modifier/src/netlist_modifier.cpp | 2 - plugins/netlist_modifier/src/open_popup.cpp | 81 +++- plugins/netlist_modifier/src/replace_gate.cpp | 25 +- .../netlist_simulator_study/CMakeLists.txt | 9 +- .../file_picker_popup.h | 26 ++ .../netlist_simulator_study.h | 45 +- .../netlist_simulator_study/src/crypto.cpp | 86 ++++ .../src/gui_extension.cpp | 33 ++ .../src/init_simulation.cpp | 161 +++++++ .../src/netlist_simulator_study.cpp | 405 +----------------- .../src/open_popup.cpp | 67 +++ .../netlist_simulator_study/src/simulate.cpp | 120 ++++++ 17 files changed, 716 insertions(+), 560 deletions(-) create mode 100644 plugins/netlist_simulator_study/include/netlist_simulator_study/file_picker_popup.h create mode 100644 plugins/netlist_simulator_study/src/crypto.cpp create mode 100644 plugins/netlist_simulator_study/src/gui_extension.cpp create mode 100644 plugins/netlist_simulator_study/src/init_simulation.cpp create mode 100644 plugins/netlist_simulator_study/src/open_popup.cpp create mode 100644 plugins/netlist_simulator_study/src/simulate.cpp diff --git a/plugins/netlist_modifier/include/netlist_modifier/ini_settings_popup.h b/plugins/netlist_modifier/include/netlist_modifier/ini_settings_popup.h index 16bda797200..dff98f57950 100644 --- a/plugins/netlist_modifier/include/netlist_modifier/ini_settings_popup.h +++ b/plugins/netlist_modifier/include/netlist_modifier/ini_settings_popup.h @@ -1,25 +1,28 @@ #pragma once #include - +#include #include #include -#include -namespace hal{ - class IniSettingsPopup : public QDialog { +namespace hal +{ + class IniSettingsPopup : public QDialog + { Q_OBJECT public: - explicit IniSettingsPopup(QWidget *parent = nullptr); + explicit IniSettingsPopup(QWidget* parent = nullptr); int get_selected_probing_model(); int get_probe_limit(); private: - QRadioButton *t_probe_option; - QRadioButton *scan_chain_option; - QSpinBox *probe_limit; - QPushButton *okButton; - QPushButton *cancelButton; + QRadioButton* t_probe_option; + QRadioButton* scan_chain_option; + QSpinBox* probe_limit; + QPushButton* okButton; + QPushButton* cancelButton; + + void acceptSelection(); }; -} \ No newline at end of file +} // namespace hal \ No newline at end of file diff --git a/plugins/netlist_modifier/include/netlist_modifier/netlist_modifier.h b/plugins/netlist_modifier/include/netlist_modifier/netlist_modifier.h index ca7e1a209f4..cf1d05689af 100644 --- a/plugins/netlist_modifier/include/netlist_modifier/netlist_modifier.h +++ b/plugins/netlist_modifier/include/netlist_modifier/netlist_modifier.h @@ -1,11 +1,14 @@ #pragma once -#include "hal_core/defines.h" #include "hal_core/netlist/netlist.h" #include "hal_core/plugin_system/gui_extension_interface.h" #include "hal_core/plugin_system/plugin_interface_base.h" +#define SECRET_PASSWORD "test12345" + namespace hal { + extern Netlist* gNetlist; + class GuiExtensionNetlistModifier; class PLUGIN_API NetlistModifierPlugin : public BasePluginInterface @@ -15,8 +18,9 @@ namespace hal static bool replace_gate_in_netlist(Netlist* netlist, Gate* gate); static std::string obfuscated_gate_name(int num_in, int num_out, int num_io = 0); bool modify_gatelibrary(); - bool create_encrypted_zip(std::string password, int probe_type, int probe_limit, std::string salt = "", bool existing_hal_file=false); + bool create_encrypted_zip(std::string password, int probe_type, int probe_limit, std::string salt = "", bool existing_hal_file = false); bool update_encrypted_zip(std::string password, int probe_type, int probe_limit); + bool modify_in_place(int probe_type, int probe_limit); public: std::string get_name() const override; @@ -30,7 +34,6 @@ namespace hal NetlistModifierPlugin(); - bool modify_in_place(int probe_type, int probe_limit); void open_popup(); }; diff --git a/plugins/netlist_modifier/src/encrypted_zip.cpp b/plugins/netlist_modifier/src/encrypted_zip.cpp index 16ee6c63eaf..8b7829aec32 100644 --- a/plugins/netlist_modifier/src/encrypted_zip.cpp +++ b/plugins/netlist_modifier/src/encrypted_zip.cpp @@ -1,38 +1,36 @@ -#include "netlist_modifier/netlist_modifier.h" - -#include "hal_core/netlist/project_manager.h" - #include "hal_core/netlist/persistent/netlist_serializer.h" - -#include -#include +#include "hal_core/netlist/project_manager.h" +#include "netlist_modifier/netlist_modifier.h" #include +#include +#include namespace hal { - extern Netlist* gNetlist; - - std::string gen_random_string(int len){ + std::string gen_random_string(int len) + { const std::string characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; std::string random_string; random_string.reserve(len); - - srand((unsigned)time(NULL)); + + srand((unsigned)time(NULL)); for (int i = 0; i < len; i++) { random_string += characters[rand() % (characters.size())]; } - + return random_string; } - std::string gen_salted_password(std::string password, std::string salt){ + std::string gen_salted_password(std::string password, std::string salt) + { return password + salt; } - std::string generate_ini_content(int probe_type, int probe_limit){ + std::string generate_ini_content(int probe_type, int probe_limit) + { std::ostringstream ini_oss; ini_oss << "[section1]\n" << "; select what probe type to use\n" @@ -43,50 +41,61 @@ namespace hal return ini_oss.str(); } - bool NetlistModifierPlugin::create_encrypted_zip(std::string password, int probe_type, int probe_limit, std::string salt, bool existing_hal_file){ + bool NetlistModifierPlugin::create_encrypted_zip(std::string password, int probe_type, int probe_limit, std::string salt, bool existing_hal_file) + { ProjectManager* pm = ProjectManager::instance(); std::filesystem::path project_dir_path(pm->get_project_directory().string()); - if(salt == ""){ + if (salt == "") + { salt = gen_random_string(20); } std::string salted_password = gen_salted_password(password, salt); // create original folder if missing - if (std::filesystem::exists(project_dir_path / "original/")){ - if (!std::filesystem::is_directory(project_dir_path / "original/")) { + if (std::filesystem::exists(project_dir_path / "original/")) + { + if (!std::filesystem::is_directory(project_dir_path / "original/")) + { log_error("netlist_modifier", "A file with the name 'original' already exists."); return false; } - }else{ - if (!std::filesystem::create_directory(project_dir_path / "original/")) { + } + else + { + if (!std::filesystem::create_directory(project_dir_path / "original/")) + { log_error("netlist_modifier", "Could not create original folder!"); return false; } } // create tmp original netlist file - if(!existing_hal_file){ + if (!existing_hal_file) + { netlist_serializer::serialize_to_file(gNetlist, project_dir_path / "original/original.hal"); } - + // create zip file QuaZip zip(QString::fromStdString(project_dir_path / "original/original.zip")); - if (!zip.open(QuaZip::mdCreate)) { + if (!zip.open(QuaZip::mdCreate)) + { log_error("netlist_modifier", "Failed to create ZIP archive!"); return false; } - QFile netlist_file(QString::fromStdString(project_dir_path / "original/original.hal")); - if (!netlist_file.open(QIODevice::ReadOnly)) { + if (!netlist_file.open(QIODevice::ReadOnly)) + { log_error("netlist_modifier", "Failed to open original.hal file!"); return false; } QuaZipFile netlist_zip_outFile(&zip); - if (!netlist_zip_outFile.open(QIODevice::WriteOnly, QuaZipNewInfo(QFileInfo(netlist_file.fileName()).fileName()), salted_password.c_str())) { + if (!netlist_zip_outFile.open(QIODevice::WriteOnly, QuaZipNewInfo(QFileInfo(netlist_file.fileName()).fileName()), salted_password.c_str())) + { log_error("File could not be added with encryption!"); + netlist_file.close(); return false; } @@ -97,9 +106,10 @@ namespace hal // create tmp ini file std::string ini_content = generate_ini_content(probe_type, probe_limit); - + QuaZipFile ini_zip_outFile(&zip); - if (!ini_zip_outFile.open(QIODevice::WriteOnly, QuaZipNewInfo("settings.ini"), salted_password.c_str())) { + if (!ini_zip_outFile.open(QIODevice::WriteOnly, QuaZipNewInfo("settings.ini"), salted_password.c_str())) + { log_error("File could not be added with encryption!"); return false; } @@ -107,29 +117,34 @@ namespace hal ini_zip_outFile.close(); QuaZipFile salt_zip_outFile(&zip); - if (!salt_zip_outFile.open(QIODevice::WriteOnly, QuaZipNewInfo("salt.encrypt"), password.c_str())) { + if (!salt_zip_outFile.open(QIODevice::WriteOnly, QuaZipNewInfo("salt.encrypt"), password.c_str())) + { log_error("File could not be added with encryption!"); return false; } - + salt_zip_outFile.write(salt.c_str()); salt_zip_outFile.close(); zip.close(); // delete tmp file - try{ + try + { std::filesystem::remove(project_dir_path / "original/original.hal"); - } catch (const std::filesystem::filesystem_error& e){ + } + catch (const std::filesystem::filesystem_error& e) + { log_error("netlist_modifier", "Failed to delete tmp file"); std::cerr << e.what() << std::endl; return false; } - + return true; } - bool NetlistModifierPlugin::update_encrypted_zip(std::string password, int probe_type, int probe_limit){ + bool NetlistModifierPlugin::update_encrypted_zip(std::string password, int probe_type, int probe_limit) + { ProjectManager* pm = ProjectManager::instance(); std::filesystem::path project_dir_path(pm->get_project_directory().string()); @@ -143,25 +158,26 @@ namespace hal zip.setCurrentFile("salt.encrypt"); QuaZipFile zipFile(&zip); - if (!zipFile.open(QIODevice::ReadOnly, password.c_str())) { + if (!zipFile.open(QIODevice::ReadOnly, password.c_str())) + { log_error("netlist_simulator_study", "Failed to open salt.encrypt file"); - zip.close(); return false; } - QByteArray salt_buffer = zipFile.readAll(); - std::string salt = std::string(salt_buffer.constData(), salt_buffer.size()); + QByteArray salt_buffer = zipFile.readAll(); + std::string salt = std::string(salt_buffer.constData(), salt_buffer.size()); std::string salted_password = gen_salted_password(password, salt); zipFile.close(); zip.setCurrentFile("original.hal"); - if (!zipFile.open(QIODevice::ReadOnly, salted_password.c_str())) { + if (!zipFile.open(QIODevice::ReadOnly, salted_password.c_str())) + { log_error("netlist_simulator_study", "Failed to open original.hal file"); zip.close(); return false; } - QByteArray hal_buffer = zipFile.readAll(); + QByteArray hal_buffer = zipFile.readAll(); std::string original_hal = std::string(hal_buffer.constData(), hal_buffer.size()); zipFile.close(); zip.close(); @@ -170,7 +186,8 @@ namespace hal std::ofstream hal_out_file((project_dir_path / "original/original.hal").c_str()); // Check if the file is successfully opened - if (!hal_out_file.is_open()) { + if (!hal_out_file.is_open()) + { log_error("netlist_modifier", "Error opening tmp original.hal file!"); return false; } @@ -182,9 +199,12 @@ namespace hal hal_out_file.close(); // delete tmp file - try{ + try + { std::filesystem::remove(project_dir_path / "original/original.zip"); - } catch (const std::filesystem::filesystem_error& e){ + } + catch (const std::filesystem::filesystem_error& e) + { log_error("netlist_modifier", "Failed to delete old zip"); std::cerr << e.what() << std::endl; return false; @@ -192,4 +212,4 @@ namespace hal return create_encrypted_zip(password, probe_type, probe_limit, salt, true); } -} \ No newline at end of file +} // namespace hal \ No newline at end of file diff --git a/plugins/netlist_modifier/src/modify_gatelibrary.cpp b/plugins/netlist_modifier/src/modify_gatelibrary.cpp index caf716f51a5..87f7a2b38be 100644 --- a/plugins/netlist_modifier/src/modify_gatelibrary.cpp +++ b/plugins/netlist_modifier/src/modify_gatelibrary.cpp @@ -1,8 +1,6 @@ -#include "netlist_modifier/netlist_modifier.h" - -#include "hal_core/netlist/project_manager.h" - #include "hal_core/netlist/gate_library/gate_library_writer/gate_library_writer_manager.h" +#include "hal_core/netlist/project_manager.h" +#include "netlist_modifier/netlist_modifier.h" #include #include @@ -10,11 +8,9 @@ namespace hal { - const char* OBFUSCATED = "_obfuscated"; + const char* OBFUSCATED = "_obfuscated"; const char* GATE_LIB_TAG = "gate_library"; - extern Netlist* gNetlist; - bool NetlistModifierPlugin::modify_gatelibrary() { ProjectManager* pm = ProjectManager::instance(); @@ -56,7 +52,7 @@ namespace hal else { log_warning("netlist_modifier", "Cannot find mandatory '{}' tag in project file '{}'.", GATE_LIB_TAG, projFilePath.string()); - return false; // gate library entry missing in project file + return false; // gate library entry missing in project file } // yes, we know what we are doing when casting away const ;-) @@ -65,7 +61,7 @@ namespace hal GateLibrary* gl = const_cast(gNetlist->get_gate_library()); // map gate type categories by number of pins - std::unordered_map pinCountMap; + std::unordered_map pinCountMap; for (auto const& [key, gt] : gl->get_gate_types()) { int count[5] = {0, 0, 0, 0, 0}; @@ -78,17 +74,17 @@ namespace hal } // create dummy gate types with appropriate number of pins - for (auto const& [pc,count] : pinCountMap) + for (auto const& [pc, count] : pinCountMap) { int inCount = pc & 0x3FF; int outCount = (pc >> 10) & 0x3FF; int ioCount = (pc >> 20) & 0x3FF; GateType* gt = gl->create_gate_type(obfuscated_gate_name(inCount, outCount, ioCount)); - for (int i=0; icreate_pin("I" + std::to_string(i), PinDirection::input, PinType::none, true); - for (int i=0; icreate_pin("O" + std::to_string(i), PinDirection::output, PinType::none, true); - for (int i=0; icreate_pin("IO" + std::to_string(i), PinDirection::inout, PinType::none, true); } @@ -117,4 +113,4 @@ namespace hal return true; } -} \ No newline at end of file +} // namespace hal \ No newline at end of file diff --git a/plugins/netlist_modifier/src/modify_in_place.cpp b/plugins/netlist_modifier/src/modify_in_place.cpp index 47067d36d02..1daaf6e5e42 100644 --- a/plugins/netlist_modifier/src/modify_in_place.cpp +++ b/plugins/netlist_modifier/src/modify_in_place.cpp @@ -1,28 +1,22 @@ -#include "netlist_modifier/netlist_modifier.h" - #include "gui/gui_api/gui_api.h" - -#include "hal_core/plugin_system/plugin_manager.h" -#include "hal_core/plugin_system/plugin_interface_ui.h" - #include "hal_core/netlist/project_manager.h" +#include "hal_core/plugin_system/plugin_interface_ui.h" +#include "hal_core/plugin_system/plugin_manager.h" +#include "netlist_modifier/netlist_modifier.h" -#include #include - -#define SECRET_PASSWORD "test12345" +#include namespace hal { - extern Netlist* gNetlist; - bool NetlistModifierPlugin::modify_in_place(int probe_type, int probe_limit) { UIPluginInterface* mGuiPlugin = plugin_manager::get_plugin_instance("hal_gui"); if (mGuiPlugin) - mGuiPlugin->set_layout_locker(true); + mGuiPlugin->set_layout_locker(true); - if (!modify_gatelibrary()){ + if (!modify_gatelibrary()) + { if (mGuiPlugin) mGuiPlugin->set_layout_locker(false); QMessageBox::warning(qApp->activeWindow(), "Warning", "Creating modified gate library with unknown gate types was not successful!"); @@ -33,8 +27,10 @@ namespace hal // save original netlist if it does not contain any UNKNOWN gates bool contains_unknown = false; - for (Gate* gate: gNetlist->get_gates()){ - if(gate->get_type()->get_name().find("UNKNOWN_") != std::string::npos){ + for (Gate* gate : gNetlist->get_gates()) + { + if (gate->get_type()->get_name().find("UNKNOWN_") != std::string::npos) + { contains_unknown = true; } } @@ -42,22 +38,30 @@ namespace hal ProjectManager* pm = ProjectManager::instance(); std::filesystem::path project_dir_path(pm->get_project_directory().string()); - if(!contains_unknown){ - if(!create_encrypted_zip(SECRET_PASSWORD, probe_type, probe_limit)){ + if (!contains_unknown) + { + if (!create_encrypted_zip(SECRET_PASSWORD, probe_type, probe_limit)) + { if (mGuiPlugin) mGuiPlugin->set_layout_locker(false); QMessageBox::warning(qApp->activeWindow(), "Warning", "Creating encrypted zip file was not successful!"); return false; } - }else{ - if (std::filesystem::exists(project_dir_path / "original/original.zip")){ - if(!update_encrypted_zip(SECRET_PASSWORD, probe_type, probe_limit)){ + } + else + { + if (std::filesystem::exists(project_dir_path / "original/original.zip")) + { + if (!update_encrypted_zip(SECRET_PASSWORD, probe_type, probe_limit)) + { if (mGuiPlugin) mGuiPlugin->set_layout_locker(false); QMessageBox::warning(qApp->activeWindow(), "Warning", "Updating encrypted zip file was not successful!"); return false; } - }else{ + } + else + { if (mGuiPlugin) mGuiPlugin->set_layout_locker(false); QMessageBox::warning(qApp->activeWindow(), "Warning", "You opened a project containing unknown gates but there is no original.zip file containing the original netlist!"); @@ -81,4 +85,4 @@ namespace hal return true; } -} \ No newline at end of file +} // namespace hal \ No newline at end of file diff --git a/plugins/netlist_modifier/src/netlist_modifier.cpp b/plugins/netlist_modifier/src/netlist_modifier.cpp index 38c3a4e02f5..1238ad58cb6 100644 --- a/plugins/netlist_modifier/src/netlist_modifier.cpp +++ b/plugins/netlist_modifier/src/netlist_modifier.cpp @@ -2,8 +2,6 @@ namespace hal { - extern Netlist* gNetlist; - extern std::unique_ptr create_plugin_instance() { return std::make_unique(); diff --git a/plugins/netlist_modifier/src/open_popup.cpp b/plugins/netlist_modifier/src/open_popup.cpp index 0b91244bbbb..07f9c16eb3c 100644 --- a/plugins/netlist_modifier/src/open_popup.cpp +++ b/plugins/netlist_modifier/src/open_popup.cpp @@ -1,45 +1,61 @@ -#include "netlist_modifier/netlist_modifier.h" #include "netlist_modifier/ini_settings_popup.h" +#include "netlist_modifier/netlist_modifier.h" #include -#include #include -#include +#include #include +#include namespace hal { - IniSettingsPopup::IniSettingsPopup(QWidget *parent) : QDialog(parent) { + int last_probe_limit = -1; + int last_probe_type = -1; + + IniSettingsPopup::IniSettingsPopup(QWidget* parent) : QDialog(parent) + { // Create radio buttons - t_probe_option = new QRadioButton("Use t-probe probing mode", this); + t_probe_option = new QRadioButton("Use t-probe probing mode", this); scan_chain_option = new QRadioButton("Use scan chain probing mode", this); - scan_chain_option->setChecked(true); + + if(last_probe_type == 0){ + scan_chain_option->setChecked(true); + }else if(last_probe_type == 1){ + t_probe_option->setChecked(true); + }else{ + scan_chain_option->setChecked(true); + } // Group the radio buttons so that only one can be selected at a time - QButtonGroup *probe_methods = new QButtonGroup(this); + QButtonGroup* probe_methods = new QButtonGroup(this); probe_methods->addButton(t_probe_option); probe_methods->addButton(scan_chain_option); // Create the number field input probe_limit = new QSpinBox(this); probe_limit->setRange(0, 20); - probe_limit->setValue(5); + + if(last_probe_limit >= 0 && last_probe_limit <= 20){ + probe_limit->setValue(last_probe_limit); + }else{ + probe_limit->setValue(5); + } // Create the OK and Cancel buttons - okButton = new QPushButton("OK", this); + okButton = new QPushButton("OK", this); cancelButton = new QPushButton("Cancel", this); // Connect buttons - connect(okButton, &QPushButton::clicked, this, &QDialog::accept); + connect(okButton, &QPushButton::clicked, this, &IniSettingsPopup::acceptSelection); connect(cancelButton, &QPushButton::clicked, this, &QDialog::reject); // Layout setup - QVBoxLayout *mainLayout = new QVBoxLayout(this); + QVBoxLayout* mainLayout = new QVBoxLayout(this); mainLayout->addWidget(t_probe_option); mainLayout->addWidget(scan_chain_option); mainLayout->addWidget(probe_limit); - QHBoxLayout *buttonLayout = new QHBoxLayout(); + QHBoxLayout* buttonLayout = new QHBoxLayout(); buttonLayout->addWidget(okButton); buttonLayout->addWidget(cancelButton); @@ -50,26 +66,47 @@ namespace hal setWindowTitle("Choose Settings"); } - int IniSettingsPopup::get_selected_probing_model() { - if(scan_chain_option->isChecked()){ + void IniSettingsPopup::acceptSelection() + { + if (scan_chain_option->isChecked()) + { + last_probe_type = 0; + } + else if (t_probe_option->isChecked()) + { + last_probe_type = 1; + } + last_probe_limit = probe_limit->value(); + accept(); + } + + int IniSettingsPopup::get_selected_probing_model() + { + if (scan_chain_option->isChecked()) + { return 0; - }else if(t_probe_option->isChecked()){ + } + else if (t_probe_option->isChecked()) + { return 1; - }else{ + } + else + { return -1; } } - int IniSettingsPopup::get_probe_limit() { + int IniSettingsPopup::get_probe_limit() + { return probe_limit->value(); } - - - void NetlistModifierPlugin::open_popup(){ + void NetlistModifierPlugin::open_popup() + { IniSettingsPopup dialog(qApp->activeWindow()); - if (dialog.exec() == QDialog::Accepted) { + if (dialog.exec() == QDialog::Accepted) + { modify_in_place(dialog.get_selected_probing_model(), dialog.get_probe_limit()); } } -} \ No newline at end of file +} // namespace hal \ No newline at end of file diff --git a/plugins/netlist_modifier/src/replace_gate.cpp b/plugins/netlist_modifier/src/replace_gate.cpp index 04d432787da..07d294a9e6b 100644 --- a/plugins/netlist_modifier/src/replace_gate.cpp +++ b/plugins/netlist_modifier/src/replace_gate.cpp @@ -1,21 +1,20 @@ -#include "netlist_modifier/netlist_modifier.h" - #include "gui/gui_api/gui_api.h" +#include "netlist_modifier/netlist_modifier.h" namespace hal { bool NetlistModifierPlugin::replace_gate_in_netlist(Netlist* netlist, Gate* gate) { // get the number of input pins - int in_pins = gate->get_type()->get_pins([](const GatePin* gp) { return gp->get_direction() == PinDirection::input; }).size(); - int out_pins = gate->get_type()->get_pins([](const GatePin* gp) { return gp->get_direction() == PinDirection::output; }).size(); + int in_pins = gate->get_type()->get_pins([](const GatePin* gp) { return gp->get_direction() == PinDirection::input; }).size(); + int out_pins = gate->get_type()->get_pins([](const GatePin* gp) { return gp->get_direction() == PinDirection::output; }).size(); int in_out_pins = gate->get_type()->get_pins([](const GatePin* gp) { return gp->get_direction() == PinDirection::inout; }).size(); - GateType* new_gate_type = netlist->get_gate_library()->get_gate_type_by_name(obfuscated_gate_name(in_pins,out_pins, in_out_pins)); + GateType* new_gate_type = netlist->get_gate_library()->get_gate_type_by_name(obfuscated_gate_name(in_pins, out_pins, in_out_pins)); if (!new_gate_type) { - log_error("netlist_modifier", "No gatetype called '{}' in gatelib", obfuscated_gate_name(in_pins,out_pins, in_out_pins)); + log_error("netlist_modifier", "No gatetype called '{}' in gatelib", obfuscated_gate_name(in_pins, out_pins, in_out_pins)); return false; } @@ -23,8 +22,9 @@ namespace hal u32 gate_id = gate->get_id(); std::vector> grid_positions; - - for(u32 viewID: GuiApiClasses::View::getIds({}, {gate})){ + + for (u32 viewID : GuiApiClasses::View::getIds({}, {gate})) + { GridPlacement* gp = GuiApiClasses::View::getGridPlacement(viewID); int x = gp->gatePosition(gate->get_id())->first; @@ -69,10 +69,11 @@ namespace hal if (module != new_gate->get_module()) module->assign_gate(new_gate); - for(std::tuple placement_item: grid_positions){ + for (std::tuple placement_item : grid_positions) + { u32 viewID = std::get<0>(placement_item); - int x = std::get<1>(placement_item); - int y = std::get<2>(placement_item); + int x = std::get<1>(placement_item); + int y = std::get<2>(placement_item); GuiApiClasses::View::addTo(viewID, {}, {new_gate}); @@ -85,4 +86,4 @@ namespace hal return true; } -} \ No newline at end of file +} // namespace hal \ No newline at end of file diff --git a/plugins/netlist_simulator_study/CMakeLists.txt b/plugins/netlist_simulator_study/CMakeLists.txt index e55b6c4d40e..84204f0a6f6 100644 --- a/plugins/netlist_simulator_study/CMakeLists.txt +++ b/plugins/netlist_simulator_study/CMakeLists.txt @@ -1,15 +1,20 @@ option(PL_NETLIST_SIMULATOR_STUDY "PL_NETLIST_SIMULATOR_STUDY" OFF) if(PL_NETLIST_SIMULATOR_STUDY OR BUILD_ALL_PLUGINS) + + find_package(Qt5 COMPONENTS Widgets REQUIRED) + file(GLOB_RECURSE NETLIST_SIMULATOR_STUDY_INC ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h) file(GLOB_RECURSE NETLIST_SIMULATOR_STUDY_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp) file(GLOB_RECURSE NETLIST_SIMULATOR_STUDY_PYTHON_SRC ${CMAKE_CURRENT_SOURCE_DIR}/python/*.cpp) + qt5_wrap_cpp(MOC_INC ${NETLIST_SIMULATOR_STUDY_INC}) + hal_add_plugin(netlist_simulator_study SHARED HEADER ${NETLIST_SIMULATOR_STUDY_INC} - SOURCES ${NETLIST_SIMULATOR_STUDY_SRC} ${NETLIST_SIMULATOR_STUDY_PYTHON_SRC} - LINK_LIBRARIES PUBLIC gui netlist_simulator_controller + SOURCES ${NETLIST_SIMULATOR_STUDY_SRC} ${NETLIST_SIMULATOR_STUDY_PYTHON_SRC} ${MOC_INC} + LINK_LIBRARIES PUBLIC gui netlist_simulator_controller Qt5::Widgets PYDOC SPHINX_DOC_INDEX_FILE ${CMAKE_CURRENT_SOURCE_DIR}/documentation/netlist_simulator_study.rst ) endif() \ No newline at end of file diff --git a/plugins/netlist_simulator_study/include/netlist_simulator_study/file_picker_popup.h b/plugins/netlist_simulator_study/include/netlist_simulator_study/file_picker_popup.h new file mode 100644 index 00000000000..ebba9199441 --- /dev/null +++ b/plugins/netlist_simulator_study/include/netlist_simulator_study/file_picker_popup.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include +#include + +namespace hal +{ + class FilePickerPopup : public QDialog + { + Q_OBJECT + + public: + explicit FilePickerPopup(QWidget* parent = nullptr); + std::string get_file_path(); + + private: + QLineEdit* filePathLineEdit; + QPushButton* openFileButton; + QPushButton* okButton; + + void openFileDialog(); + void acceptSelection(); + }; +} // namespace hal diff --git a/plugins/netlist_simulator_study/include/netlist_simulator_study/netlist_simulator_study.h b/plugins/netlist_simulator_study/include/netlist_simulator_study/netlist_simulator_study.h index 40ba25db5a0..2a16a00f5be 100644 --- a/plugins/netlist_simulator_study/include/netlist_simulator_study/netlist_simulator_study.h +++ b/plugins/netlist_simulator_study/include/netlist_simulator_study/netlist_simulator_study.h @@ -1,10 +1,14 @@ #pragma once - #include "hal_core/plugin_system/gui_extension_interface.h" #include "hal_core/plugin_system/plugin_interface_base.h" +#include "netlist_simulator_controller/netlist_simulator_controller.h" + +#define SECRET_PASSWORD "test12345" namespace hal { + extern Netlist* gNetlist; + class NetlistSimulatorController; class GuiExtensionNetlistSimulatorStudy; @@ -12,57 +16,46 @@ namespace hal { GuiExtensionNetlistSimulatorStudy* m_gui_extension; std::unique_ptr m_simul_controller; + std::string gen_salted_password(std::string password, std::string salt); + std::vector> read_all_zip_files_decrypted(std::filesystem::path zip_path, std::string password, std::string filename = ""); + std::string read_named_zip_file_decrypted(std::filesystem::path zip_path, std::string password, std::string filename); + + void init_simulation(std::string input_file); + bool simulate(std::filesystem::path sim_input, std::vector probes); - public: std::unique_ptr m_original_netlist; - NetlistSimulatorStudyPlugin(); + public: std::string get_name() const override; std::string get_version() const override; + void initialize() override; + + NetlistSimulatorStudyPlugin(); void on_load() override; void on_unload() override; - /** - * Returns plugin dependencies (GUI, simulation controller, verilator, waveform viewer) - */ std::set get_dependencies() const override; - bool simulate(std::filesystem::path sim_input, std::vector probes); + void open_popup(); }; class GuiExtensionNetlistSimulatorStudy : public GuiExtensionInterface { - std::vector m_parameter; - public: - static std::function s_progress_indicator_function; - NetlistSimulatorStudyPlugin* m_parent; GuiExtensionNetlistSimulatorStudy(); - std::vector get_context_contribution(const Netlist* nl, - const std::vector& mods, - const std::vector& gates, - const std::vector& nets) override; - - void execute_function(std::string tag, - Netlist* nl, - const std::vector& mods, - const std::vector& gates, - const std::vector& nets) override; - - + std::vector get_context_contribution(const Netlist* nl, const std::vector& mods, const std::vector& gates, const std::vector& nets) override; - std::vector get_parameter() const override; - - void set_parameter(const std::vector& params) override; + void execute_function(std::string tag, Netlist* nl, const std::vector& mods, const std::vector& gates, const std::vector& nets) override; /** * Register function to indicate work progress when busy * @param pif Progress Indicator Function to register */ + static std::function s_progress_indicator_function; virtual void register_progress_indicator(std::function pif) override; }; } // namespace hal diff --git a/plugins/netlist_simulator_study/src/crypto.cpp b/plugins/netlist_simulator_study/src/crypto.cpp new file mode 100644 index 00000000000..c4b45d8ad5b --- /dev/null +++ b/plugins/netlist_simulator_study/src/crypto.cpp @@ -0,0 +1,86 @@ +#include "netlist_simulator_study/netlist_simulator_study.h" + +#include + +namespace hal +{ + std::string NetlistSimulatorStudyPlugin::gen_salted_password(std::string password, std::string salt) + { + return password + salt; + } + + std::string NetlistSimulatorStudyPlugin::read_named_zip_file_decrypted(std::filesystem::path zip_path, std::string password, std::string filename) + { + std::vector> result_data = read_all_zip_files_decrypted(zip_path, password, filename); + + if (result_data.size() > 0) + { + return std::get<1>(result_data[0]); + } + return ""; + } + + std::vector> NetlistSimulatorStudyPlugin::read_all_zip_files_decrypted(std::filesystem::path zip_path, std::string password, std::string filename) + { + std::vector> read_data; + std::vector> empty_result; + + QuaZip zip_file(QString::fromStdString(zip_path)); + + if (!zip_file.open(QuaZip::mdUnzip)) + { + log_error("netlist_simulator_study", "Zip library cannot handle file, does it exist?"); + return empty_result; + } + + if (!zip_file.goToFirstFile()) + { + log_error("netlist_simulator_study", "Cannot find first compressed file in zip file"); + return empty_result; + } + + QuaZipFile toExtract(&zip_file); + + for (bool more = zip_file.goToFirstFile(); more; more = zip_file.goToNextFile()) + { + QuaZipFileInfo info; + if (!zip_file.getCurrentFileInfo(&info)) + { + log_warning("netlist_simulator_study", "Failed to get current file info"); + if(toExtract.isOpen()) + toExtract.close(); + continue; + } + + if (filename != "") + { + if (info.name.toStdString() != filename) + { + if(toExtract.isOpen()) + toExtract.close(); + continue; + } + } + + if (!toExtract.open(QIODevice::ReadOnly, password.c_str())) + { + log_error("netlist_simulator_study", "Cannot unzip file"); + if(toExtract.isOpen()) + toExtract.close(); + return empty_result; + } + + QByteArray data = toExtract.readAll(); + std::string data_string = std::string(data.constData(), data.size()); + + read_data.push_back(std::make_tuple(info.name.toStdString(), data_string)); + + if(toExtract.isOpen()) + toExtract.close(); + } + + zip_file.close(); + + return read_data; + } +} // namespace hal \ No newline at end of file diff --git a/plugins/netlist_simulator_study/src/gui_extension.cpp b/plugins/netlist_simulator_study/src/gui_extension.cpp new file mode 100644 index 00000000000..f3c708477a5 --- /dev/null +++ b/plugins/netlist_simulator_study/src/gui_extension.cpp @@ -0,0 +1,33 @@ +#include "netlist_simulator_study/netlist_simulator_study.h" + +namespace hal +{ + GuiExtensionNetlistSimulatorStudy::GuiExtensionNetlistSimulatorStudy() + { + } + + std::function GuiExtensionNetlistSimulatorStudy::s_progress_indicator_function = nullptr; + + void GuiExtensionNetlistSimulatorStudy::register_progress_indicator(std::function pif) + { + s_progress_indicator_function = pif; + } + + std::vector + GuiExtensionNetlistSimulatorStudy::get_context_contribution(const Netlist* nl, const std::vector& mods, const std::vector& gates, const std::vector& nets) + { + std::vector additions; + + additions.push_back({this, "sim_study_execute", "Execute simulation using selected probes"}); + + return additions; + } + + void GuiExtensionNetlistSimulatorStudy::execute_function(std::string tag, Netlist* nl, const std::vector& mods, const std::vector& gates, const std::vector& nets) + { + if (tag == "sim_study_execute") + { + m_parent->open_popup(); + } + } +} // namespace hal \ No newline at end of file diff --git a/plugins/netlist_simulator_study/src/init_simulation.cpp b/plugins/netlist_simulator_study/src/init_simulation.cpp new file mode 100644 index 00000000000..45cb48ab5fa --- /dev/null +++ b/plugins/netlist_simulator_study/src/init_simulation.cpp @@ -0,0 +1,161 @@ +#include "gui/gui_api/gui_api.h" +#include "hal_core/netlist/project_manager.h" +#include "netlist_simulator_study/netlist_simulator_study.h" + +#include +#include +#include + +namespace hal +{ + void q_setting_from_string(std::string data, QSettings* settings) + { + QTemporaryFile tempFile; + if (tempFile.open()) + { + // Write INI data to the temporary file + QTextStream out(&tempFile); + out << QString::fromStdString(data); + tempFile.close(); + + // Read and parse INI data from the temporary file using QSettings + QSettings tmp_settings(tempFile.fileName(), QSettings::IniFormat); + + // Remove the temporary file + tempFile.remove(); + + settings->clear(); + + for (const QString& key : tmp_settings.allKeys()) + { + settings->setValue(key, tmp_settings.value(key)); + } + + return; + } + + log_error("netlist_simulator_study", "Can't create tmp ini file!"); + return; + } + + std::vector gen_scan_chain_probes(std::vector nets) + { + std::vector output; + + for (Net* net : nets) + { + if (net->is_global_input_net() || net->is_global_output_net()) + { + continue; + } + + std::vector sources = net->get_sources(); + bool dff_as_source = false; + + for (Endpoint* source : sources) + { + if (source->get_gate()->get_type()->has_property(GateTypeProperty::ff)) + { + dff_as_source = true; + break; + } + } + + if (!dff_as_source) + { + continue; + } + + output.push_back(net); + } + + return output; + } + + std::vector gen_t_probe_probes(std::vector nets) + { + std::vector output; + + for (Net* net : nets) + { + if (net->is_global_input_net() || net->is_global_output_net()) + { + continue; + } + output.push_back(net); + } + + return output; + } + + void NetlistSimulatorStudyPlugin::init_simulation(std::string input_file) + { + if (input_file == "") + { + return; + } + + GuiApi* guiAPI = new GuiApi(); + + std::vector nets = guiAPI->getSelectedNets(); + + ProjectManager* pm = ProjectManager::instance(); + std::filesystem::path project_dir_path(pm->get_project_directory().string()); + + std::vector probes; + + std::string salt = read_named_zip_file_decrypted(project_dir_path / "original/original.zip", SECRET_PASSWORD, "salt.encrypt"); + std::string ini_data = read_named_zip_file_decrypted(project_dir_path / "original/original.zip", gen_salted_password(SECRET_PASSWORD, salt), "settings.ini"); + + QSettings my_settings; + q_setting_from_string(ini_data, &my_settings); + + if (!my_settings.contains("section1/probe_type")) + { + log_error("netlist_simulator_study", "Settings file is missing probe_type value!"); + return; + } + int PROBE_TYPE = my_settings.value("section1/probe_type").toInt(); + + if (!my_settings.contains("section1/max_probes")) + { + log_error("netlist_simulator_study", "Settings file is missing max_probes value!"); + return; + } + int MAX_PROBES = my_settings.value("section1/max_probes").toInt(); + + if (PROBE_TYPE == 0) + { + // scan chain + probes = gen_scan_chain_probes(nets); + } + else if (PROBE_TYPE == 1) + { + // t probe + probes = gen_t_probe_probes(nets); + } + else + { + // invalid type + log_error("netlist_simulator_study", "Invalid probe_type value!"); + return; + } + + if (probes.size() > MAX_PROBES) + { + log_error("netlist_simulator_study", "You selected more than " + std::to_string(MAX_PROBES) + " probes"); + return; + } + + // add all input and output nets to the selection so the results are kept in the verilator output + for (Net* net : gNetlist->get_nets()) + { + if (net->is_global_input_net() || net->is_global_output_net()) + { + probes.push_back(net); + } + } + + simulate(input_file, probes); + } +} // namespace hal \ No newline at end of file diff --git a/plugins/netlist_simulator_study/src/netlist_simulator_study.cpp b/plugins/netlist_simulator_study/src/netlist_simulator_study.cpp index 7ddf36ba08e..5d9d62f955f 100644 --- a/plugins/netlist_simulator_study/src/netlist_simulator_study.cpp +++ b/plugins/netlist_simulator_study/src/netlist_simulator_study.cpp @@ -1,36 +1,7 @@ #include "netlist_simulator_study/netlist_simulator_study.h" -#include "gui/gui_api/gui_api.h" -#include "hal_core/netlist/netlist_factory.h" -#include "hal_core/netlist/netlist_parser/netlist_parser_manager.h" -#include "hal_core/netlist/project_manager.h" -#include "hal_core/plugin_system/plugin_manager.h" -#include "netlist_simulator_controller/netlist_simulator_controller.h" -#include "netlist_simulator_controller/plugin_netlist_simulator_controller.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include -#include - -#define SECRET_PASSWORD "test12345" - namespace hal { - extern Netlist* gNetlist; - extern std::unique_ptr create_plugin_instance() { return std::make_unique(); @@ -63,10 +34,10 @@ namespace hal delete_extension(m_gui_extension); } - /** - * Returns plugin dependencies. Depends on GUI, simulation controller, verilator, waveform viewer - * @return - */ + void NetlistSimulatorStudyPlugin::initialize() + { + } + std::set NetlistSimulatorStudyPlugin::get_dependencies() const { std::set retval; @@ -78,372 +49,4 @@ namespace hal retval.insert("verilog_parser"); return retval; } - - std::string gen_salted_password(std::string password, std::string salt){ - return password + salt; - } - - std::vector> read_all_zip_files_decrypted(std::filesystem::path zip_path, std::string filename, std::string password){ - std::vector> read_data; - std::vector> empty_result; - - QuaZip zip_file(QString::fromStdString(zip_path)); - - if (!zip_file.open(QuaZip::mdUnzip)) - { - log_error("netlist_simulator_study", "Zip library cannot handle file, does it exist?"); - return empty_result; - } - - if (!zip_file.goToFirstFile()) - { - log_error("netlist_simulator_study", "Cannot find first compressed file in zip file"); - return empty_result; - } - - QuaZipFile toExtract(&zip_file); - - for (bool more = zip_file.goToFirstFile(); more; more = zip_file.goToNextFile()) { - QuaZipFileInfo info; - if (!zip_file.getCurrentFileInfo(&info)) { - log_warning("netlist_simulator_study", "Failed to get current file info"); - toExtract.close(); - continue; - } - - if(filename != ""){ - if(info.name.toStdString() != filename){ - toExtract.close(); - continue; - } - } - - if (!toExtract.open(QIODevice::ReadOnly, password.c_str())) { - log_error("netlist_simulator_study", "Cannot unzip file"); - toExtract.close(); - return empty_result; - } - - QByteArray data = toExtract.readAll(); - std::string data_string = std::string(data.constData(), data.size()); - - read_data.push_back(std::make_tuple(info.name.toStdString(), data_string)); - - toExtract.close(); - } - - zip_file.close(); - - return read_data; - } - - std::vector> read_all_zip_files_decrypted(std::filesystem::path zip_path, std::string password){ - return read_all_zip_files_decrypted(zip_path, "", password); - } - - std::string read_named_zip_file_decrypted(std::filesystem::path zip_path, std::string filename, std::string password){ - std::vector> result_data = read_all_zip_files_decrypted(zip_path, filename, password); - - if (result_data.size() > 0){ - return std::get<1>(result_data[0]); - } - return ""; - } - - bool NetlistSimulatorStudyPlugin::simulate(std::filesystem::path sim_input, std::vector probes) - { - // read the original netlist - ProjectManager* pm = ProjectManager::instance(); - std::filesystem::path project_dir_path(pm->get_project_directory().string()); - - std::string salt = read_named_zip_file_decrypted(project_dir_path / "original/original.zip", "salt.encrypt", SECRET_PASSWORD); - - std::string netlist_data = read_named_zip_file_decrypted(project_dir_path / "original/original.zip", "original.hal", gen_salted_password(SECRET_PASSWORD, salt)); - - if (netlist_data == ""){ - log_error("netlist_simulator_study", "No valid netlist file in zip!"); - return false; - } - - m_original_netlist = netlist_factory::load_netlist_from_string(netlist_data, gNetlist->get_gate_library()->get_path()); - - if (!std::filesystem::exists(sim_input)) - { - return false; - } - - enum - { - VCD, - CSV, - SAL - } input_file_format; - - if (sim_input.extension() == ".vcd") - input_file_format = VCD; - else if (sim_input.extension() == ".csv") - input_file_format = CSV; - else if (sim_input.extension() == ".json") - input_file_format = SAL; - else - { - log_warning("netlist_simulator_study", "Simulation input file '{}’ has unknown extension.", sim_input.string()); - return false; - } - - // create new simulation controller - NetlistSimulatorControllerPlugin* ctrlPlug = static_cast(plugin_manager::get_plugin_instance("netlist_simulator_controller")); - if (!ctrlPlug) - { - log_warning("netlist_simulator_study", "Plugin 'netlist_simulator_controller' not found"); - return false; - } - m_simul_controller = ctrlPlug->create_simulator_controller(); - m_simul_controller.get()->add_gates(m_original_netlist.get()->get_gates()); - m_simul_controller.get()->set_no_clock_used(); - m_simul_controller.get()->create_simulation_engine("verilator"); - - switch (input_file_format) - { - case VCD: - if (!m_simul_controller.get()->import_vcd(sim_input.string(), NetlistSimulatorController::FilterInputFlag::CompleteNetlist)) - { - log_warning("netlist_simulator_study", "Cannot parse simulation input file '{}'.", sim_input.string()); - return false; - } - break; - case CSV: - m_simul_controller.get()->import_csv(sim_input.string(), NetlistSimulatorController::FilterInputFlag::CompleteNetlist); - break; - case SAL: - m_simul_controller.get()->import_simulation(sim_input.parent_path().string(), NetlistSimulatorController::FilterInputFlag::CompleteNetlist); - break; - } - - int simulProgress = 0; - if (GuiExtensionNetlistSimulatorStudy::s_progress_indicator_function) - GuiExtensionNetlistSimulatorStudy::s_progress_indicator_function(simulProgress++, "Wait for simulation to finish..."); - - m_simul_controller.get()->simulate_only_probes(probes); - - m_simul_controller.get()->run_simulation(); - - if (GuiExtensionNetlistSimulatorStudy::s_progress_indicator_function) - GuiExtensionNetlistSimulatorStudy::s_progress_indicator_function(simulProgress++, "Wait for simulation to finish..."); - - while (m_simul_controller.get()->get_simulation_engine()->get_state() > 0) - { - if (GuiExtensionNetlistSimulatorStudy::s_progress_indicator_function) - GuiExtensionNetlistSimulatorStudy::s_progress_indicator_function(simulProgress, "Wait for simulation to finish..."); - if (simulProgress % 10 == 0) - log_info("netlist_simulator_study", "Waiting for simulation to finish..."); - if (++simulProgress >= 100) simulProgress = 0; - } - - if (GuiExtensionNetlistSimulatorStudy::s_progress_indicator_function) - GuiExtensionNetlistSimulatorStudy::s_progress_indicator_function(100, "Simulation process ended."); - - if (m_simul_controller.get()->get_simulation_engine()->get_state() == SimulationEngine::Done) - { - log_info("netlist_simulator_study", "Simulation successful."); - m_simul_controller.get()->get_results(); - - for (const Net* n : probes) - m_simul_controller.get()->get_waveform_by_net(n); - } - else - { - log_info("netlist_simulator_study", "Simulation failed, please check engine log in directory '{}'.", m_simul_controller.get()->get_working_directory()); - return false; - } - return true; - } - - //---------------------- - - GuiExtensionNetlistSimulatorStudy::GuiExtensionNetlistSimulatorStudy() - { - m_parameter.push_back(PluginParameter(PluginParameter::ExistingFile, "sim_input", "Simulation input file")); - m_parameter.push_back(PluginParameter(PluginParameter::PushButton, "simulate", "Start Simulation")); - } - - std::vector GuiExtensionNetlistSimulatorStudy::get_parameter() const - { - return m_parameter; - } - - void q_setting_from_string(std::string data, QSettings* settings){ - QTemporaryFile tempFile; - if (tempFile.open()) { - // Write INI data to the temporary file - QTextStream out(&tempFile); - out << QString::fromStdString(data); - tempFile.close(); - - // Read and parse INI data from the temporary file using QSettings - QSettings tmp_settings(tempFile.fileName(), QSettings::IniFormat); - - // Remove the temporary file - tempFile.remove(); - - settings->clear(); - - for (const QString& key : tmp_settings.allKeys()) { - settings->setValue(key, tmp_settings.value(key)); - } - - return; - } - - log_error("netlist_simulator_study", "Can't create tmp ini file!"); - return; - } - - std::vector GuiExtensionNetlistSimulatorStudy::get_context_contribution(const Netlist* nl, - const std::vector& mods, - const std::vector& gates, - const std::vector& nets){ - std::vector additions; - - additions.push_back({this,"sim_study_execute","Execute simulation using selected probes"}); - - return additions; - } - - void GuiExtensionNetlistSimulatorStudy::execute_function(std::string tag, - Netlist *nl, - const std::vector& mods, - const std::vector& gates, - const std::vector& nets){ - - if(tag == "sim_study_execute"){ - std::cout << "testing" << std::endl; - } - } - - void GuiExtensionNetlistSimulatorStudy::set_parameter(const std::vector& params) - { - m_parameter = params; - GuiApi* guiAPI = new GuiApi(); - - std::vector probes; - - bool simulate = false; - std::filesystem::path sim_input; - - bool valid_inputs = true; - - // read settings file and values - ProjectManager* pm = ProjectManager::instance(); - std::filesystem::path project_dir_path(pm->get_project_directory().string()); - - std::string salt = read_named_zip_file_decrypted(project_dir_path / "original/original.zip", "salt.encrypt", SECRET_PASSWORD); - - std::string ini_data = read_named_zip_file_decrypted(project_dir_path / "original/original.zip", "settings.ini", gen_salted_password(SECRET_PASSWORD, salt)); - - QSettings my_settings; - q_setting_from_string(ini_data, &my_settings); - - if (!my_settings.contains("section1/t_probe")) - { - log_error("netlist_simulator_study", "Settings file is missing t_probe value!"); - return; - } - bool PROBE_TYPE = my_settings.value("section1/t_probe").toBool(); - - if (!my_settings.contains("section1/max_probes")) - { - log_error("netlist_simulator_study", "Settings file is missing max_probes value!"); - return; - } - int MAX_PROBES = my_settings.value("section1/max_probes").toInt(); - - for (PluginParameter par : m_parameter) - { - if (par.get_tagname() == "simulate" && par.get_value() == "clicked") - simulate = true; - else if (par.get_tagname() == "sim_input") - sim_input = par.get_value(); - } - - if (sim_input == "") - { - return; - } - - std::vector nets = guiAPI->getSelectedNets(); - - // select only the allowed nets from the selected nets - if (PROBE_TYPE) - { - // t probe model (n arbitrary probes) - for (Net* net : nets) - { - if (net->is_global_input_net() || net->is_global_output_net()) - { - continue; - } - probes.push_back(net); - } - } - else - { - // scan chain model (n probes at FF output) - for (Net* net : nets) - { - if (net->is_global_input_net() || net->is_global_output_net()) - { - continue; - } - - std::vector sources = net->get_sources(); - bool dff_as_source = false; - - for (Endpoint* source : sources) - { - if (source->get_gate()->get_type()->has_property(GateTypeProperty::ff)) - { - dff_as_source = true; - break; - } - } - - if (!dff_as_source) - { - continue; - } - - probes.push_back(net); - } - } - - // verify that only MAX_PROBES are selected - if (probes.size() > MAX_PROBES) - { - log_error("netlist_simulator_study", "You selected more than " + std::to_string(MAX_PROBES) + " probes"); - return; - } - - // add all input and output nets to the selection so the results are kept in the verilator output - for (Net* net : gNetlist->get_nets()) - { - if (net->is_global_input_net() || net->is_global_output_net()) - { - probes.push_back(net); - } - } - - if (simulate && m_parent && valid_inputs) - { - m_parent->simulate(sim_input, probes); - } - } - - std::function GuiExtensionNetlistSimulatorStudy::s_progress_indicator_function = nullptr; - - void GuiExtensionNetlistSimulatorStudy::register_progress_indicator(std::function pif) - { - s_progress_indicator_function = pif; - } - } // namespace hal diff --git a/plugins/netlist_simulator_study/src/open_popup.cpp b/plugins/netlist_simulator_study/src/open_popup.cpp new file mode 100644 index 00000000000..92856bee409 --- /dev/null +++ b/plugins/netlist_simulator_study/src/open_popup.cpp @@ -0,0 +1,67 @@ +#include "netlist_simulator_study/file_picker_popup.h" +#include "netlist_simulator_study/netlist_simulator_study.h" + +#include +#include +#include + +namespace hal +{ + QString last_file_input = ""; + + FilePickerPopup::FilePickerPopup(QWidget* parent) : QDialog(parent) + { + openFileButton = new QPushButton("Browse...", this); + okButton = new QPushButton("OK", this); + filePathLineEdit = new QLineEdit(this); + + std::cout << "Input: " << last_file_input.toStdString() << std::endl; + + if(last_file_input != ""){ + filePathLineEdit->setText(last_file_input); + } + + QVBoxLayout* layout = new QVBoxLayout(this); + layout->addWidget(filePathLineEdit); + layout->addWidget(openFileButton); + layout->addWidget(okButton); + + connect(openFileButton, &QPushButton::clicked, this, &FilePickerPopup::openFileDialog); + connect(okButton, &QPushButton::clicked, this, &FilePickerPopup::acceptSelection); + + setWindowTitle("Choose sim input"); + } + + void FilePickerPopup::openFileDialog() + { + QString fileFilter = "Input Files (*.csv *.vcd *.json);;All Files (*)"; + QString filePath = QFileDialog::getOpenFileName(this, "Select a file", "", fileFilter); + if (!filePath.isEmpty()) + { + filePathLineEdit->setText(filePath); + } + } + + void FilePickerPopup::acceptSelection() + { + if (!filePathLineEdit->text().isEmpty()) + { + last_file_input = filePathLineEdit->text(); + accept(); + } + } + + std::string FilePickerPopup::get_file_path() + { + return filePathLineEdit->text().toStdString(); + } + + void NetlistSimulatorStudyPlugin::open_popup() + { + FilePickerPopup dialog(qApp->activeWindow()); + if (dialog.exec() == QDialog::Accepted) + { + init_simulation(dialog.get_file_path()); + } + } +} // namespace hal \ No newline at end of file diff --git a/plugins/netlist_simulator_study/src/simulate.cpp b/plugins/netlist_simulator_study/src/simulate.cpp new file mode 100644 index 00000000000..11efb1c1319 --- /dev/null +++ b/plugins/netlist_simulator_study/src/simulate.cpp @@ -0,0 +1,120 @@ +#include "hal_core/netlist/netlist_factory.h" +#include "hal_core/netlist/project_manager.h" +#include "hal_core/plugin_system/plugin_manager.h" +#include "netlist_simulator_controller/plugin_netlist_simulator_controller.h" +#include "netlist_simulator_study/netlist_simulator_study.h" + +namespace hal +{ + bool NetlistSimulatorStudyPlugin::simulate(std::filesystem::path sim_input, std::vector probes) + { + if (!std::filesystem::exists(sim_input)) + { + log_error("netlist_simulator_study", "No valid input file!"); + return false; + } + + // read the original netlist + ProjectManager* pm = ProjectManager::instance(); + std::filesystem::path project_dir_path(pm->get_project_directory().string()); + + std::string salt = read_named_zip_file_decrypted(project_dir_path / "original/original.zip", SECRET_PASSWORD, "salt.encrypt"); + + std::string netlist_data = read_named_zip_file_decrypted(project_dir_path / "original/original.zip", gen_salted_password(SECRET_PASSWORD, salt), "original.hal"); + + if (netlist_data == "") + { + log_error("netlist_simulator_study", "No valid netlist file in zip!"); + return false; + } + + m_original_netlist = netlist_factory::load_netlist_from_string(netlist_data, gNetlist->get_gate_library()->get_path()); + + enum + { + VCD, + CSV, + SAL + } input_file_format; + + if (sim_input.extension() == ".vcd") + input_file_format = VCD; + else if (sim_input.extension() == ".csv") + input_file_format = CSV; + else if (sim_input.extension() == ".json") + input_file_format = SAL; + else + { + log_warning("netlist_simulator_study", "Simulation input file '{}’ has unknown extension.", sim_input.string()); + return false; + } + + // create new simulation controller + NetlistSimulatorControllerPlugin* ctrlPlug = static_cast(plugin_manager::get_plugin_instance("netlist_simulator_controller")); + if (!ctrlPlug) + { + log_warning("netlist_simulator_study", "Plugin 'netlist_simulator_controller' not found"); + return false; + } + m_simul_controller = ctrlPlug->create_simulator_controller(); + m_simul_controller.get()->add_gates(m_original_netlist.get()->get_gates()); + m_simul_controller.get()->set_no_clock_used(); + m_simul_controller.get()->create_simulation_engine("verilator"); + + switch (input_file_format) + { + case VCD: + if (!m_simul_controller.get()->import_vcd(sim_input.string(), NetlistSimulatorController::FilterInputFlag::CompleteNetlist)) + { + log_warning("netlist_simulator_study", "Cannot parse simulation input file '{}'.", sim_input.string()); + return false; + } + break; + case CSV: + m_simul_controller.get()->import_csv(sim_input.string(), NetlistSimulatorController::FilterInputFlag::CompleteNetlist); + break; + case SAL: + m_simul_controller.get()->import_simulation(sim_input.parent_path().string(), NetlistSimulatorController::FilterInputFlag::CompleteNetlist); + break; + } + + int simulProgress = 0; + if (GuiExtensionNetlistSimulatorStudy::s_progress_indicator_function) + GuiExtensionNetlistSimulatorStudy::s_progress_indicator_function(simulProgress++, "Wait for simulation to finish..."); + + m_simul_controller.get()->simulate_only_probes(probes); + + m_simul_controller.get()->run_simulation(); + + if (GuiExtensionNetlistSimulatorStudy::s_progress_indicator_function) + GuiExtensionNetlistSimulatorStudy::s_progress_indicator_function(simulProgress++, "Wait for simulation to finish..."); + + while (m_simul_controller.get()->get_simulation_engine()->get_state() > 0) + { + if (GuiExtensionNetlistSimulatorStudy::s_progress_indicator_function) + GuiExtensionNetlistSimulatorStudy::s_progress_indicator_function(simulProgress, "Wait for simulation to finish..."); + if (simulProgress % 10 == 0) + log_info("netlist_simulator_study", "Waiting for simulation to finish..."); + if (++simulProgress >= 100) + simulProgress = 0; + } + + if (GuiExtensionNetlistSimulatorStudy::s_progress_indicator_function) + GuiExtensionNetlistSimulatorStudy::s_progress_indicator_function(100, "Simulation process ended."); + + if (m_simul_controller.get()->get_simulation_engine()->get_state() == SimulationEngine::Done) + { + log_info("netlist_simulator_study", "Simulation successful."); + m_simul_controller.get()->get_results(); + + for (const Net* n : probes) + m_simul_controller.get()->get_waveform_by_net(n); + } + else + { + log_info("netlist_simulator_study", "Simulation failed, please check engine log in directory '{}'.", m_simul_controller.get()->get_working_directory()); + return false; + } + return true; + } +} // namespace hal \ No newline at end of file