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 969cd86190a..05cdb3dc1ad 100644 --- a/plugins/netlist_modifier/include/netlist_modifier/ini_settings_popup.h +++ b/plugins/netlist_modifier/include/netlist_modifier/ini_settings_popup.h @@ -5,6 +5,11 @@ #include #include +/** + * @brief Header file for the pop up used to select the options for the ini file like probing type and probe limit + * + */ + namespace hal { class IniSettingsPopup : public QDialog diff --git a/plugins/netlist_modifier/include/netlist_modifier/netlist_modifier.h b/plugins/netlist_modifier/include/netlist_modifier/netlist_modifier.h index cf1d05689af..0b7fb31f36e 100644 --- a/plugins/netlist_modifier/include/netlist_modifier/netlist_modifier.h +++ b/plugins/netlist_modifier/include/netlist_modifier/netlist_modifier.h @@ -5,6 +5,11 @@ #define SECRET_PASSWORD "test12345" +/** + * @brief Header file for the netlist modifier plugin. This plugin is used by the researcher to replace some gates with gates of an unknown type + * + */ + namespace hal { extern Netlist* gNetlist; diff --git a/plugins/netlist_modifier/src/encrypted_zip.cpp b/plugins/netlist_modifier/src/encrypted_zip.cpp index 8b7829aec32..86752411bbb 100644 --- a/plugins/netlist_modifier/src/encrypted_zip.cpp +++ b/plugins/netlist_modifier/src/encrypted_zip.cpp @@ -6,10 +6,22 @@ #include #include +/** + * @brief This file contains the methods to encrypt the original netlist and the ini file into an encrypted zip archive + * + */ + namespace hal { + /** + * @brief This function return a random alphanumerical string with a given length + * + * @param len The length of the generated random string + * @return std::string The generated random string + */ std::string gen_random_string(int len) { + // list of allowed symbols const std::string characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; std::string random_string; random_string.reserve(len); @@ -24,11 +36,25 @@ namespace hal return random_string; } + /** + * @brief This function generates a salted password based on a given password and a salt. + * + * @param password The initial password + * @param salt The salt that should be used for the salting process + * @return std::string The salted password + */ std::string gen_salted_password(std::string password, std::string salt) { return password + salt; } + /** + * @brief This function creates the content of the ini file given the desired settings + * + * @param probe_type The desired probe type. Currently this value can be 0 (scan chain probing) or 1 (t probing) + * @param probe_limit The desired maximum number of allowed probes + * @return std::string The generated content of the ini file + */ std::string generate_ini_content(int probe_type, int probe_limit) { std::ostringstream ini_oss; @@ -41,11 +67,23 @@ namespace hal return ini_oss.str(); } + /** + * @brief Function to create the encrypted zip archive with a given password and settings like probe-type + * + * @param password The password used for the encryption + * @param probe_type the probe type that should be stored in the ini file + * @param probe_limit the probe limit that should be stored in the ini file + * @param salt (optional) The salt used for encryption. If a empty string is provided as the salt a random one is generated + * @param existing_hal_file boolean whether or not a copy of the original unaltered hal file exists or if the current netlist needs to be saved + * @return bool returns true on success + */ bool NetlistModifierPlugin::create_encrypted_zip(std::string password, int probe_type, int probe_limit, std::string salt, bool existing_hal_file) { + // get the path to the current project directory ProjectManager* pm = ProjectManager::instance(); std::filesystem::path project_dir_path(pm->get_project_directory().string()); + // generate salt if no salt is provided if (salt == "") { salt = gen_random_string(20); @@ -85,6 +123,7 @@ namespace hal return false; } + // write the original netlist file to the zip archive. Use the salted password for encryption QFile netlist_file(QString::fromStdString(project_dir_path / "original/original.hal")); if (!netlist_file.open(QIODevice::ReadOnly)) { @@ -107,6 +146,7 @@ namespace hal // create tmp ini file std::string ini_content = generate_ini_content(probe_type, probe_limit); + // write the ini file to the zip archive. Use the salted password for encryption QuaZipFile ini_zip_outFile(&zip); if (!ini_zip_outFile.open(QIODevice::WriteOnly, QuaZipNewInfo("settings.ini"), salted_password.c_str())) { @@ -116,13 +156,13 @@ namespace hal ini_zip_outFile.write(ini_content.c_str()); ini_zip_outFile.close(); + // write the used salt to the zip archive. Use the original unsalted password for enryption QuaZipFile salt_zip_outFile(&zip); 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(); @@ -143,11 +183,21 @@ namespace hal return true; } + /** + * @brief This function updates an existing zip archive if just the settings of the ini got changed + * + * @param password The password used for encrypting + * @param probe_type The probe type that should be stored in the ini file + * @param probe_limit the probe limit that should be stored in the ini file + * @return bool Returns true on success + */ bool NetlistModifierPlugin::update_encrypted_zip(std::string password, int probe_type, int probe_limit) { + // get the path to the current project directory ProjectManager* pm = ProjectManager::instance(); std::filesystem::path project_dir_path(pm->get_project_directory().string()); + // open the existing zip archive QuaZip zip(QString::fromStdString(project_dir_path / "original/original.zip")); if (!zip.open(QuaZip::mdUnzip)) @@ -156,6 +206,7 @@ namespace hal return false; } + // retrieve the salt from the zip archive zip.setCurrentFile("salt.encrypt"); QuaZipFile zipFile(&zip); if (!zipFile.open(QIODevice::ReadOnly, password.c_str())) @@ -164,11 +215,13 @@ namespace hal return false; } + // generate the salted password that was used to encrypt the other files 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(); + // retrieve the original netlist and write it to a tmp file zip.setCurrentFile("original.hal"); if (!zipFile.open(QIODevice::ReadOnly, salted_password.c_str())) { @@ -210,6 +263,7 @@ namespace hal return false; } + // create the new encrypted zip archive using the new settings return create_encrypted_zip(password, probe_type, probe_limit, salt, true); } } // namespace hal \ No newline at end of file diff --git a/plugins/netlist_modifier/src/gui_extension.cpp b/plugins/netlist_modifier/src/gui_extension.cpp index 8be7be45c6b..cd622725e2a 100644 --- a/plugins/netlist_modifier/src/gui_extension.cpp +++ b/plugins/netlist_modifier/src/gui_extension.cpp @@ -6,6 +6,15 @@ namespace hal { } + /** + * @brief This functions adds the item to the right click menu of the HAL GUI + * + * @param nl + * @param mods + * @param gates + * @param nets + * @return std::vector + */ std::vector GuiExtensionNetlistModifier::get_context_contribution(const Netlist* nl, const std::vector& mods, const std::vector& gates, const std::vector& nets) { @@ -16,6 +25,15 @@ namespace hal return additions; } + /** + * @brief This functions handles the event if the user selects the new right click menu entry + * + * @param tag + * @param nl + * @param mods + * @param gates + * @param nets + */ void GuiExtensionNetlistModifier::execute_function(std::string tag, Netlist* nl, const std::vector& mods, const std::vector& gates, const std::vector& nets) { if (tag == "modify_in_place") diff --git a/plugins/netlist_modifier/src/modify_gatelibrary.cpp b/plugins/netlist_modifier/src/modify_gatelibrary.cpp index 87f7a2b38be..4d95dcb27d1 100644 --- a/plugins/netlist_modifier/src/modify_gatelibrary.cpp +++ b/plugins/netlist_modifier/src/modify_gatelibrary.cpp @@ -6,13 +6,24 @@ #include #include +/** + * @brief This file contains the functionalities to generate the modified netlist with the obfuscated gate types + * + */ + namespace hal { const char* OBFUSCATED = "_obfuscated"; const char* GATE_LIB_TAG = "gate_library"; + /** + * @brief This function reads the current gate lib and adds for each input/output size of the contained cells an obfuscated version. + * + * @return bool true on success + */ bool NetlistModifierPlugin::modify_gatelibrary() { + // open the current project directory ProjectManager* pm = ProjectManager::instance(); std::filesystem::path projFilePath(pm->get_project_directory()); diff --git a/plugins/netlist_modifier/src/modify_in_place.cpp b/plugins/netlist_modifier/src/modify_in_place.cpp index 1daaf6e5e42..06371969602 100644 --- a/plugins/netlist_modifier/src/modify_in_place.cpp +++ b/plugins/netlist_modifier/src/modify_in_place.cpp @@ -9,12 +9,21 @@ namespace hal { + /** + * @brief This functions replaces all the selected gates with a gate of an unknown gate type + * + * @param probe_type The allowed probe type that should be written in the ini file + * @param probe_limit The allowed probe limit that should be written in the ini file + * @return bool true in success + */ bool NetlistModifierPlugin::modify_in_place(int probe_type, int probe_limit) { + // lock the GUI so the view is not updated for every replaced gate individually but rather only once when all gates are replaced UIPluginInterface* mGuiPlugin = plugin_manager::get_plugin_instance("hal_gui"); if (mGuiPlugin) mGuiPlugin->set_layout_locker(true); + // modify the gate lib if (!modify_gatelibrary()) { if (mGuiPlugin) @@ -23,6 +32,7 @@ namespace hal return false; } + // get all selected gates to replace them std::vector gates = GuiApi().getSelectedGates(); // save original netlist if it does not contain any UNKNOWN gates @@ -38,6 +48,7 @@ namespace hal ProjectManager* pm = ProjectManager::instance(); std::filesystem::path project_dir_path(pm->get_project_directory().string()); + // If the netlist does not contain any unknown gates then create the encrypted zip archive if (!contains_unknown) { if (!create_encrypted_zip(SECRET_PASSWORD, probe_type, probe_limit)) @@ -48,6 +59,7 @@ namespace hal return false; } } + // if the netlist already contains unknown gates then just update the existing zip archive else { if (std::filesystem::exists(project_dir_path / "original/original.zip")) @@ -69,6 +81,7 @@ namespace hal } } + // iterate over all selected gates and replace them one by one for (Gate* gate : gates) { if (!replace_gate_in_netlist(gNetlist, gate)) @@ -79,7 +92,8 @@ namespace hal return false; } } - + + // release the layout lock once finished if (mGuiPlugin) mGuiPlugin->set_layout_locker(false); diff --git a/plugins/netlist_modifier/src/netlist_modifier.cpp b/plugins/netlist_modifier/src/netlist_modifier.cpp index 1238ad58cb6..5ea3e1b0b25 100644 --- a/plugins/netlist_modifier/src/netlist_modifier.cpp +++ b/plugins/netlist_modifier/src/netlist_modifier.cpp @@ -47,6 +47,14 @@ namespace hal { } + /** + * @brief This function generates the new gate type name based on the number of input and output pins + * + * @param num_in Number of input pins to the gate + * @param num_out Number of output pins to the gate + * @param num_io Number of io pins to the gate + * @return std::string The newly generated gate type name + */ std::string NetlistModifierPlugin::obfuscated_gate_name(int num_in, int num_out, int num_io) { std::string retval = "UNKNOWN_" + std::to_string(num_in) + "IN_" + std::to_string(num_out) + "OUT"; diff --git a/plugins/netlist_modifier/src/open_popup.cpp b/plugins/netlist_modifier/src/open_popup.cpp index 9c32144d93f..f9dec9d0f9d 100644 --- a/plugins/netlist_modifier/src/open_popup.cpp +++ b/plugins/netlist_modifier/src/open_popup.cpp @@ -12,6 +12,11 @@ namespace hal int IniSettingsPopup::last_probe_limit = -1; int IniSettingsPopup::last_probe_type = -1; + /** + * @brief Construct a new Ini Settings Popup:: Ini Settings Popup object + * + * @param parent + */ IniSettingsPopup::IniSettingsPopup(QWidget* parent) : QDialog(parent) { // Create radio buttons @@ -66,6 +71,10 @@ namespace hal setWindowTitle("Choose Settings"); } + /** + * @brief Handles the event for clicking the accept button + * + */ void IniSettingsPopup::acceptSelection() { if (scan_chain_option->isChecked()) @@ -80,6 +89,11 @@ namespace hal accept(); } + /** + * @brief Returns the selected probing type method + * + * @return int + */ int IniSettingsPopup::get_selected_probing_model() { if (scan_chain_option->isChecked()) @@ -96,11 +110,20 @@ namespace hal } } + /** + * @brief Returns the selected probing limit + * + * @return int + */ int IniSettingsPopup::get_probe_limit() { return probe_limit->value(); } + /** + * @brief Function that is called when clicking the right click menu entry. This function creates the popup hand handles accept event and calls the gate replacement method + * + */ void NetlistModifierPlugin::open_popup() { IniSettingsPopup dialog(qApp->activeWindow()); diff --git a/plugins/netlist_modifier/src/replace_gate.cpp b/plugins/netlist_modifier/src/replace_gate.cpp index 07d294a9e6b..95d58f0cc5d 100644 --- a/plugins/netlist_modifier/src/replace_gate.cpp +++ b/plugins/netlist_modifier/src/replace_gate.cpp @@ -3,6 +3,13 @@ namespace hal { + /** + * @brief This function replaces a given gate with a gate of an unknown type with the same input and output pin size + * + * @param netlist A pointer to the current netlist + * @param gate The gate that should be replaced + * @return bool true on success + */ bool NetlistModifierPlugin::replace_gate_in_netlist(Netlist* netlist, Gate* gate) { // get the number of input pins @@ -10,6 +17,7 @@ namespace hal 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(); + // get the obfuscated gate type from the gate lib 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) @@ -21,6 +29,7 @@ namespace hal std::string gate_name = "UNKNOWN_" + std::to_string(gate->get_id()); u32 gate_id = gate->get_id(); + // save the grid positions for all the views where this gate is included std::vector> grid_positions; for (u32 viewID : GuiApiClasses::View::getIds({}, {gate})) @@ -32,19 +41,29 @@ namespace hal grid_positions.emplace_back(viewID, x, y); } + // remember the module assignment Module* module = gate->get_module(); std::vector in_nets; std::vector out_nets; // save the input and output nets - for (Net* net : gate->get_fan_in_nets()) + for (GatePin* pin: gate->get_type()->get_input_pins()) { - in_nets.push_back(net); + if(gate->get_fan_in_endpoint(pin->get_name())){ + in_nets.push_back(gate->get_fan_in_endpoint(pin->get_name())->get_net()); + }else{ + in_nets.push_back(NULL); + } } - for (Net* net : gate->get_fan_out_nets()) + + for (GatePin* pin: gate->get_type()->get_output_pins()) { - out_nets.push_back(net); + if(gate->get_fan_out_endpoint(pin->get_name())){ + out_nets.push_back(gate->get_fan_out_endpoint(pin->get_name())->get_net()); + }else{ + out_nets.push_back(NULL); + } } // delete old gate and add new one @@ -55,20 +74,26 @@ namespace hal int counter = 0; for (Net* net : in_nets) { - net->add_destination(new_gate, "I" + std::to_string(counter)); + if(net){ + net->add_destination(new_gate, "I" + std::to_string(counter)); + } counter++; } counter = 0; for (Net* net : out_nets) { - net->add_source(new_gate, "O" + std::to_string(counter)); + if(net){ + net->add_source(new_gate, "O" + std::to_string(counter)); + } counter++; } + // assign the new gate to the same module if (module != new_gate->get_module()) module->assign_gate(new_gate); + // update all the grid positions in all the views for (std::tuple placement_item : grid_positions) { u32 viewID = std::get<0>(placement_item); 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 index 744c1a3497a..2f1ae320471 100644 --- 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 @@ -5,6 +5,11 @@ #include #include +/** + * @brief Header file for the pop up used to select the simulation input file and start the simulation + * + */ + namespace hal { class FilePickerPopup : public QDialog 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 2a16a00f5be..fa325fa0ba8 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 @@ -5,6 +5,11 @@ #define SECRET_PASSWORD "test12345" +/** + * @brief Header file for the netlist simulation study plugin. This plugin is used by the study participants to simulate the original unaltered netlist + * + */ + namespace hal { extern Netlist* gNetlist; @@ -21,6 +26,7 @@ namespace hal 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); + void init_simulation_internal(std::string input_file, std::vector nets); bool simulate(std::filesystem::path sim_input, std::vector probes); std::unique_ptr m_original_netlist; @@ -38,6 +44,8 @@ namespace hal std::set get_dependencies() const override; void open_popup(); + + void init_simulation_from_python(std::string input_file, std::vector nets); }; class GuiExtensionNetlistSimulatorStudy : public GuiExtensionInterface diff --git a/plugins/netlist_simulator_study/python/python_bindings.cpp b/plugins/netlist_simulator_study/python/python_bindings.cpp new file mode 100644 index 00000000000..3edcfa7c058 --- /dev/null +++ b/plugins/netlist_simulator_study/python/python_bindings.cpp @@ -0,0 +1,40 @@ +#include "hal_core/python_bindings/python_bindings.h" + +#include "netlist_simulator_study/netlist_simulator_study.h" +#include "pybind11/operators.h" +#include "pybind11/pybind11.h" +#include "pybind11/stl.h" +#include "pybind11/stl_bind.h" + +namespace py = pybind11; + +namespace hal +{ + // the name in PYBIND11_MODULE/PYBIND11_PLUGIN *MUST* match the filename of the output library (without extension), + // otherwise you will get "ImportError: dynamic module does not define module export function" when importing the module + +#ifdef PYBIND11_MODULE + PYBIND11_MODULE(netlist_simulator_study, m) + { + m.doc() = "hal netlist_simulator_study python bindings"; +#else + PYBIND11_PLUGIN(netlist_modifier) + { + py::module m("netlist_simulator_study", "hal netlist_simulator_study python bindings"); +#endif + + // define all exposed functions + py::class_, BasePluginInterface>(m, "NetlistSimulatorStudyPlugin") + .def_property_readonly("name", &NetlistSimulatorStudyPlugin::get_name) + .def("get_name", &NetlistSimulatorStudyPlugin::get_name) + .def_property_readonly("version", &NetlistSimulatorStudyPlugin::get_version) + .def("get_version", &NetlistSimulatorStudyPlugin::get_version) + // python handler to stat the simulation from a python script + .def("init_simulation", &NetlistSimulatorStudyPlugin::init_simulation_from_python, py::arg("input_file"), py::arg("probe_nets")) + .def(py::init<>()); + +#ifndef PYBIND11_MODULE + return m.ptr(); +#endif + } +} // namespace hal \ No newline at end of file diff --git a/plugins/netlist_simulator_study/src/crypto.cpp b/plugins/netlist_simulator_study/src/crypto.cpp index c4b45d8ad5b..abfd5e0ebfc 100644 --- a/plugins/netlist_simulator_study/src/crypto.cpp +++ b/plugins/netlist_simulator_study/src/crypto.cpp @@ -2,13 +2,33 @@ #include +/** + * @brief This file handles the functionalities of decrypting password protected zip archives + * + */ + namespace hal { + /** + * @brief This function generates a salted password based on a given password and a salt. + * + * @param password The initial password + * @param salt The salt that should be used for the salting process + * @return std::string The salted password + */ std::string NetlistSimulatorStudyPlugin::gen_salted_password(std::string password, std::string salt) { return password + salt; } + /** + * @brief This function returns the content of a specific file from within the password protected zip archive + * + * @param zip_path The path to the password protected zip archive + * @param password The password to decrypt the zip archive + * @param filename The filename of the file that should be read + * @return std::string Return either the content of the specified file or an empty string of no such file exits + */ 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); @@ -20,11 +40,20 @@ namespace hal return ""; } + /** + * @brief This function returns the content of all the files from within the password protected zip archive + * + * @param zip_path The path to the password protected zip archive + * @param password The password to decrypt the zip archive + * @param filename (optional) If a filename is provided only this file is decrypted. If this is a empty string all the files are decrypted + * @return std::vector> + */ 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; + // open the zip archive QuaZip zip_file(QString::fromStdString(zip_path)); if (!zip_file.open(QuaZip::mdUnzip)) @@ -41,8 +70,10 @@ namespace hal QuaZipFile toExtract(&zip_file); + // iterate over all the files in the zip archive and decrypt the content for (bool more = zip_file.goToFirstFile(); more; more = zip_file.goToNextFile()) { + // get file info QuaZipFileInfo info; if (!zip_file.getCurrentFileInfo(&info)) { @@ -52,6 +83,7 @@ namespace hal continue; } + // if a desired filename is provided check if the current file is the one which is searched if (filename != "") { if (info.name.toStdString() != filename) @@ -62,6 +94,7 @@ namespace hal } } + // decrypt the file and read the content if (!toExtract.open(QIODevice::ReadOnly, password.c_str())) { log_error("netlist_simulator_study", "Cannot unzip file"); @@ -70,6 +103,7 @@ namespace hal return empty_result; } + // save the content together with the filename in an tuple QByteArray data = toExtract.readAll(); std::string data_string = std::string(data.constData(), data.size()); diff --git a/plugins/netlist_simulator_study/src/gui_extension.cpp b/plugins/netlist_simulator_study/src/gui_extension.cpp index f3c708477a5..f909ca54946 100644 --- a/plugins/netlist_simulator_study/src/gui_extension.cpp +++ b/plugins/netlist_simulator_study/src/gui_extension.cpp @@ -13,6 +13,15 @@ namespace hal s_progress_indicator_function = pif; } + /** + * @brief This functions adds the item to the right click menu of the HAL GUI + * + * @param nl + * @param mods + * @param gates + * @param nets + * @return std::vector + */ std::vector GuiExtensionNetlistSimulatorStudy::get_context_contribution(const Netlist* nl, const std::vector& mods, const std::vector& gates, const std::vector& nets) { @@ -23,6 +32,15 @@ namespace hal return additions; } + /** + * @brief This functions handles the event if the user selects the new right click menu entry + * + * @param tag + * @param nl + * @param mods + * @param gates + * @param nets + */ 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") diff --git a/plugins/netlist_simulator_study/src/init_simulation.cpp b/plugins/netlist_simulator_study/src/init_simulation.cpp index 45cb48ab5fa..9bc9427aa23 100644 --- a/plugins/netlist_simulator_study/src/init_simulation.cpp +++ b/plugins/netlist_simulator_study/src/init_simulation.cpp @@ -8,6 +8,12 @@ namespace hal { + /** + * @brief This function creates a QSettings ini file from a string containing the content of the ini file. The resulting QSetting file is written to the QSetting object provided as a parameter + * + * @param data String containing the data that should be written to the QSetting object + * @param settings A pointer to a QSetting object where the data should be written to + */ void q_setting_from_string(std::string data, QSettings* settings) { QTemporaryFile tempFile; @@ -26,6 +32,7 @@ namespace hal settings->clear(); + // add all the key/value pairs to the new Settings object for (const QString& key : tmp_settings.allKeys()) { settings->setValue(key, tmp_settings.value(key)); @@ -38,12 +45,19 @@ namespace hal return; } + /** + * @brief Given a set of nets that should be probed this function filters out all the once that are not valid probes. In this case only nets that are at the output of a flip flip are valid. Also all global input and outputs are filtered out as these are probed automaticaly and do not count towards the maximum probing limit + * + * @param nets List of nets that should be probed + * @return std::vector List of all the allowed probes + */ std::vector gen_scan_chain_probes(std::vector nets) { std::vector output; for (Net* net : nets) { + // ignore the net if it is a global input or output if (net->is_global_input_net() || net->is_global_output_net()) { continue; @@ -52,6 +66,7 @@ namespace hal std::vector sources = net->get_sources(); bool dff_as_source = false; + // iterate over all sources and check if one of them is a flip flop for (Endpoint* source : sources) { if (source->get_gate()->get_type()->has_property(GateTypeProperty::ff)) @@ -61,6 +76,7 @@ namespace hal } } + // ignore the net if it is not the output net of a flip flop if (!dff_as_source) { continue; @@ -72,12 +88,18 @@ namespace hal return output; } + /** + * @brief Given a set of nets that should be probed this function filters out all the once that are not valid probes. Also all global input and outputs are filtered out as these are probed automaticaly and do not count towards the maximum probing limit + * + * @param nets + * @return std::vector + */ std::vector gen_t_probe_probes(std::vector nets) { std::vector output; - for (Net* net : nets) { + // ignore the net if it is a global input or output if (net->is_global_input_net() || net->is_global_output_net()) { continue; @@ -88,28 +110,59 @@ namespace hal return output; } + /** + * @brief Function that is called if the python binding is used + * + * @param input_file Path to the input file for the simulation + * @param nets List of nets that should be probed + */ + void NetlistSimulatorStudyPlugin::init_simulation_from_python(std::string input_file, std::vector nets){ + init_simulation_internal(input_file, nets); + } + + /** + * @brief Function that is called if the simulation is started from the GUi popup + * + * @param input_file Path to the input file for the simulation + */ void NetlistSimulatorStudyPlugin::init_simulation(std::string input_file) { + GuiApi* guiAPI = new GuiApi(); + + // get all selected nets as probes + std::vector nets = guiAPI->getSelectedNets(); + + init_simulation_internal(input_file, nets); + } + + /** + * @brief This function evaluates if the submitted nets are valid probes and if the maximum number of probes is not exceeded. If everything is okay the simulation is started + * + * @param input_file Path to the input file for the simulation + * @param nets List of nets that should be probed + */ + void NetlistSimulatorStudyPlugin::init_simulation_internal(std::string input_file, std::vector nets) + { + // check if a path is submitted 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; + // read the salt from the encrypted zip archive and use it to decrypt the ini file 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"); + // create a QSetting object from the content of the ini file QSettings my_settings; q_setting_from_string(ini_data, &my_settings); + // read the probe type and probe limit from the settings if (!my_settings.contains("section1/probe_type")) { log_error("netlist_simulator_study", "Settings file is missing probe_type value!"); @@ -124,6 +177,10 @@ namespace hal } int MAX_PROBES = my_settings.value("section1/max_probes").toInt(); + std::cout << PROBE_TYPE << std::endl; + std::cout << MAX_PROBES << std::endl; + + // filter out the invalid probes depending on the probing method if (PROBE_TYPE == 0) { // scan chain @@ -141,6 +198,7 @@ namespace hal return; } + // test if the maximum probing limit is exceeded if (probes.size() > MAX_PROBES) { log_error("netlist_simulator_study", "You selected more than " + std::to_string(MAX_PROBES) + " probes"); @@ -156,6 +214,7 @@ namespace hal } } + // start the simulation with the given input file and the probes simulate(input_file, probes); } } // namespace hal \ No newline at end of file diff --git a/plugins/netlist_simulator_study/src/open_popup.cpp b/plugins/netlist_simulator_study/src/open_popup.cpp index 33b0d74b0c1..335a5829d63 100644 --- a/plugins/netlist_simulator_study/src/open_popup.cpp +++ b/plugins/netlist_simulator_study/src/open_popup.cpp @@ -9,6 +9,11 @@ namespace hal { QString FilePickerPopup::last_file_input = ""; + /** + * @brief Construct a new File Picker Popup:: File Picker Popup object + * + * @param parent + */ FilePickerPopup::FilePickerPopup(QWidget* parent) : QDialog(parent) { openFileButton = new QPushButton("Browse...", this); @@ -32,6 +37,10 @@ namespace hal setWindowTitle("Choose sim input"); } + /** + * @brief Function to open up the system file picker window + * + */ void FilePickerPopup::openFileDialog() { QString fileFilter = "Input Files (*.csv *.vcd *.json);;All Files (*)"; @@ -42,6 +51,10 @@ namespace hal } } + /** + * @brief Handles the event for clicking the accept button + * + */ void FilePickerPopup::acceptSelection() { if (!filePathLineEdit->text().isEmpty()) @@ -51,11 +64,20 @@ namespace hal } } + /** + * @brief Returns the user specified file path + * + * @return std::string + */ std::string FilePickerPopup::get_file_path() { return filePathLineEdit->text().toStdString(); } + /** + * @brief Function that is called when clicking the right click menu entry. This function creates the popup hand handles accept event and calls the simulation init function + * + */ void NetlistSimulatorStudyPlugin::open_popup() { FilePickerPopup dialog(qApp->activeWindow()); diff --git a/plugins/netlist_simulator_study/src/simulate.cpp b/plugins/netlist_simulator_study/src/simulate.cpp index 11efb1c1319..798d0fe5129 100644 --- a/plugins/netlist_simulator_study/src/simulate.cpp +++ b/plugins/netlist_simulator_study/src/simulate.cpp @@ -6,8 +6,16 @@ namespace hal { + /** + * @brief This function executed the simulation of the original unaltered netlist given the selected probes. One the nets of the probes are later visible in the waveform viewer. All the other ones are deleted + * + * @param sim_input The input file for the simulation + * @param probes The selected probes + * @return bool true on success + */ bool NetlistSimulatorStudyPlugin::simulate(std::filesystem::path sim_input, std::vector probes) { + // test if the input file exists if (!std::filesystem::exists(sim_input)) { log_error("netlist_simulator_study", "No valid input file!"); @@ -22,14 +30,17 @@ namespace hal std::string netlist_data = read_named_zip_file_decrypted(project_dir_path / "original/original.zip", gen_salted_password(SECRET_PASSWORD, salt), "original.hal"); + // check if the netlist exists if (netlist_data == "") { log_error("netlist_simulator_study", "No valid netlist file in zip!"); return false; } + // create a netlist object from the content of the file m_original_netlist = netlist_factory::load_netlist_from_string(netlist_data, gNetlist->get_gate_library()->get_path()); + // select the correct file format of the input file enum { VCD, @@ -61,6 +72,7 @@ namespace hal m_simul_controller.get()->set_no_clock_used(); m_simul_controller.get()->create_simulation_engine("verilator"); + // import the simulation input file depending on the file format switch (input_file_format) { case VCD: @@ -78,10 +90,12 @@ namespace hal break; } + // Start the loading animation int simulProgress = 0; if (GuiExtensionNetlistSimulatorStudy::s_progress_indicator_function) GuiExtensionNetlistSimulatorStudy::s_progress_indicator_function(simulProgress++, "Wait for simulation to finish..."); + // start the simulation m_simul_controller.get()->simulate_only_probes(probes); m_simul_controller.get()->run_simulation(); @@ -102,6 +116,7 @@ namespace hal if (GuiExtensionNetlistSimulatorStudy::s_progress_indicator_function) GuiExtensionNetlistSimulatorStudy::s_progress_indicator_function(100, "Simulation process ended."); + // once the simulation is done save all the waveforms of the probes if (m_simul_controller.get()->get_simulation_engine()->get_state() == SimulationEngine::Done) { log_info("netlist_simulator_study", "Simulation successful.");