From 588aa95b47f610208762701886685310b667f7b9 Mon Sep 17 00:00:00 2001 From: Ole Engelbrecht Date: Fri, 21 Jun 2024 10:28:07 +0200 Subject: [PATCH] improved import of original netlist, gui selection for modifier, ini with settings, dynamic import/export with out hard coded paths --- plugins/netlist_modifier/CMakeLists.txt | 1 + .../netlist_modifier/netlist_modifier.h | 53 ++-- .../python/python_bindings.cpp | 40 ++-- .../netlist_modifier/src/netlist_modifier.cpp | 226 ++++++++++++------ .../netlist_simulator_study.h | 10 +- .../src/netlist_simulator_study.cpp | 139 +++++++---- 6 files changed, 288 insertions(+), 181 deletions(-) diff --git a/plugins/netlist_modifier/CMakeLists.txt b/plugins/netlist_modifier/CMakeLists.txt index 29735bf7cd4..ba59ce7a9b6 100644 --- a/plugins/netlist_modifier/CMakeLists.txt +++ b/plugins/netlist_modifier/CMakeLists.txt @@ -9,6 +9,7 @@ if(PL_NETLIST_MODIFIER OR BUILD_ALL_PLUGINS) SHARED HEADER ${NETLIST_MODIFIER_INC} SOURCES ${NETLIST_MODIFIER_SRC} ${NETLIST_MODIFIER_PYTHON_SRC} + LINK_LIBRARIES PUBLIC gui netlist_simulator_controller PYDOC SPHINX_DOC_INDEX_FILE ${CMAKE_CURRENT_SOURCE_DIR}/documentation/netlist_modifier.rst ) endif() \ 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 5bb0f0d7003..188e36cf96a 100644 --- a/plugins/netlist_modifier/include/netlist_modifier/netlist_modifier.h +++ b/plugins/netlist_modifier/include/netlist_modifier/netlist_modifier.h @@ -1,41 +1,35 @@ -#pragma once -#include "hal_core/defines.h" -#include "hal_core/plugin_system/plugin_interface_base.h" +#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/utilities/result.h" -#include "hal_core/netlist/netlist.h" +#include "hal_core/plugin_system/plugin_interface_base.h" +#include "hal_core/utilities/result.h" -namespace hal +namespace hal { - class GuiExtensionNetlistModifier; - - class PLUGIN_API NetlistModifierPlugin : public BasePluginInterface - { - GuiExtensionNetlistModifier* m_gui_extension; - - public: - std::string get_name() const override; - std::string get_version() const override; - void initialize() override; - - void on_load() override; - void on_unload() override; + class GuiExtensionNetlistModifier; - std::set get_dependencies() const override; + class PLUGIN_API NetlistModifierPlugin : public BasePluginInterface + { + GuiExtensionNetlistModifier* m_gui_extension; - NetlistModifierPlugin(); + public: + std::string get_name() const override; + std::string get_version() const override; + void initialize() override; - bool create_modified_netlist(); + void on_load() override; + void on_unload() override; - static Netlist* modified_netlist_pointer; - private: - - bool replace_gates(); - }; + std::set get_dependencies() const override; + NetlistModifierPlugin(); + bool modify_in_place(); + bool save(); + }; - class GuiExtensionNetlistModifier : public GuiExtensionInterface + class GuiExtensionNetlistModifier : public GuiExtensionInterface { std::vector m_parameter; @@ -47,6 +41,5 @@ namespace hal std::vector get_parameter() const override; void set_parameter(const std::vector& params) override; - }; -} // namespace hal \ No newline at end of file +} // namespace hal \ No newline at end of file diff --git a/plugins/netlist_modifier/python/python_bindings.cpp b/plugins/netlist_modifier/python/python_bindings.cpp index aa1223b2b16..1904cd8abb2 100644 --- a/plugins/netlist_modifier/python/python_bindings.cpp +++ b/plugins/netlist_modifier/python/python_bindings.cpp @@ -13,30 +13,28 @@ 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_modifier, m) - { - m.doc() = "hal netlist modifier python bindings"; - #else - PYBIND11_PLUGIN(netlist_modifier) - { - py::module m("netlist_modifier", "hal netlist modifier python bindings"); - #endif - - // define all exposed functions - py::class_, BasePluginInterface>(m, "NetlistModifierPlugin") +#ifdef PYBIND11_MODULE + PYBIND11_MODULE(netlist_modifier, m) + { + m.doc() = "hal netlist modifier python bindings"; +#else + PYBIND11_PLUGIN(netlist_modifier) + { + py::module m("netlist_modifier", "hal netlist modifier python bindings"); +#endif + + // define all exposed functions + py::class_, BasePluginInterface>(m, "NetlistModifierPlugin") .def_property_readonly("name", &NetlistModifierPlugin::get_name) .def("get_name", &NetlistModifierPlugin::get_name) .def_property_readonly("version", &NetlistModifierPlugin::get_version) .def("get_version", &NetlistModifierPlugin::get_version) .def(py::init<>()) - .def( - "create_modified_netlist", - &NetlistModifierPlugin::create_modified_netlist - ); + .def("modify_in_place", &NetlistModifierPlugin::modify_in_place) + .def("save", &NetlistModifierPlugin::save); - #ifndef PYBIND11_MODULE - return m.ptr(); - #endif - } -} // namespace hal \ No newline at end of file +#ifndef PYBIND11_MODULE + return m.ptr(); +#endif + } +} // 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 955f7367b1f..7e8745098b1 100644 --- a/plugins/netlist_modifier/src/netlist_modifier.cpp +++ b/plugins/netlist_modifier/src/netlist_modifier.cpp @@ -1,27 +1,30 @@ #include "netlist_modifier/netlist_modifier.h" #include "boost/functional/hash.hpp" +#include "gui/gui_api/gui_api.h" #include "hal_core/netlist/gate.h" +#include "hal_core/netlist/gate_library/gate_library_manager.h" #include "hal_core/netlist/module.h" +#include "hal_core/netlist/netlist_factory.h" #include "hal_core/netlist/netlist_writer/netlist_writer_manager.h" +#include "hal_core/netlist/project_manager.h" #include - -#include "hal_core/netlist/netlist_factory.h" +#include +#include namespace hal { extern Netlist* gNetlist; - Netlist* NetlistModifierPlugin::modified_netlist_pointer = nullptr; - extern std::unique_ptr create_plugin_instance() { return std::make_unique(); } - NetlistModifierPlugin::NetlistModifierPlugin(){ + NetlistModifierPlugin::NetlistModifierPlugin() + { m_gui_extension = nullptr; } @@ -37,7 +40,7 @@ namespace hal void NetlistModifierPlugin::on_load() { - m_gui_extension = new GuiExtensionNetlistModifier; + m_gui_extension = new GuiExtensionNetlistModifier; m_gui_extension->m_parent = this; m_extensions.push_back(m_gui_extension); } @@ -48,115 +51,184 @@ namespace hal } std::set NetlistModifierPlugin::get_dependencies() const - { - std::set retval; - retval.insert("hal_gui"); - retval.insert("verilog_writer"); - return retval; - } + { + std::set retval; + retval.insert("hal_gui"); + retval.insert("verilog_writer"); + return retval; + } void NetlistModifierPlugin::initialize() { } - bool NetlistModifierPlugin::replace_gates(){ - auto gates = NetlistModifierPlugin::modified_netlist_pointer->get_gates(); + bool replace_gate_in_netlist(Netlist* netlist, Gate* gate) + { + // get the number of input pins + int num_of_in = gate->get_fan_in_endpoints().size(); + int num_of_out = gate->get_fan_out_endpoints().size(); - for(Gate* gate: gates){ - // std::cout << gate->get_type()->to_string() << std::endl; + GateType* new_gate_type = netlist->get_gate_library()->get_gate_type_by_name("UNKNOWN_" + std::to_string(num_of_in) + "IN_" + std::to_string(num_of_out) + "OUT"); - if(gate->get_type()->to_string() == "AND"){ - GateType* new_gate_type = NetlistModifierPlugin::modified_netlist_pointer->get_gate_library()->get_gate_type_by_name("UNKNOWN_2IN"); - std::string gate_name = gate->get_name(); - u32 gate_id = gate->get_id(); + if (!new_gate_type) + { + log_error("netlist_modifier", "No gatetype called 'UNKNOWN_" + std::to_string(num_of_in) + "IN_" + std::to_string(num_of_out) + "OUT' in gatelib"); + return false; + } - std::map predecessors; - std::map successors; + /* + // dynamicly creating missing gatetype does not work as returned gatelib by netlist is const and adding type does not work + if (!new_gate_type){ + // gate type does not exist in gatelib + new_gate_type = netlist->get_gate_library()->create_gate_type("UNKNOWN_"+std::to_string(num_of_in)+"IN_"+std::to_string(num_of_out)+"OUT"); - // gate->get_successor() results in errors???? - for(Endpoint* endpoint: gate->get_fan_in_endpoints()){ - predecessors[endpoint->get_pin()->get_name()] = endpoint->get_net(); - } + for (int i = 0; i < num_of_in; i++) + { + new_gate_type->create_pin("IN_"+std::to_string(i), PinDirection::input); + } - for(Endpoint* endpoint: gate->get_fan_out_endpoints()){ - successors[endpoint->get_pin()->get_name()] = endpoint->get_net(); - } + for (int i = 0; i < num_of_out; i++) + { + new_gate_type->create_pin("OUT_"+std::to_string(i), PinDirection::output); + } + }*/ - NetlistModifierPlugin::modified_netlist_pointer->delete_gate(gate); + std::string gate_name = "UNKNOWN_" + std::to_string(gate->get_id()); + u32 gate_id = gate->get_id(); - Gate* new_gate = NetlistModifierPlugin::modified_netlist_pointer->create_gate(gate_id, new_gate_type, gate_name); + std::vector in_nets; + std::vector out_nets; - for(auto entry: predecessors){ - entry.second->add_destination(new_gate, entry.first); - } + // save the input and output nets + for (Endpoint* ep : gate->get_fan_in_endpoints()) + { + in_nets.push_back(ep->get_net()); + } + for (Endpoint* ep : gate->get_fan_out_endpoints()) + { + out_nets.push_back(ep->get_net()); + } - for(auto entry: successors){ - entry.second->add_source(new_gate, entry.first); - } - } + // delete old gate and add new one + netlist->delete_gate(gate); + Gate* new_gate = netlist->create_gate(gate_id, new_gate_type, gate_name); + + // add old connections + int counter = 1; + for (Net* net : in_nets) + { + net->add_destination(new_gate, "IN_" + std::to_string(counter)); + counter++; + } + + counter = 1; + for (Net* net : out_nets) + { + net->add_source(new_gate, "OUT_" + std::to_string(counter)); + counter++; } return true; } - bool NetlistModifierPlugin::create_modified_netlist(){ - std::cout << gNetlist->get_gates().size() << std::endl; + bool NetlistModifierPlugin::modify_in_place() + { + GuiApi* guiAPI = new GuiApi(); - auto tmp = gNetlist->copy(); - NetlistModifierPlugin::modified_netlist_pointer = std::move(tmp.get().get()); + /* + // loading copy does not work as one can not add a type to the second gatelib and adding a gate of this type to the netlist if the gatelib of the gui does not have this type + ProjectManager* pm = ProjectManager::instance(); - replace_gates(); + std::filesystem::path project_dir_path(pm->get_project_directory().string()); - replace_gates(); + if (!std::filesystem::exists(project_dir_path/"generated/gatelib_obfuscated.hgl")) + { + if (std::filesystem::exists(project_dir_path/"generated") && !std::filesystem::is_directory(project_dir_path/"generated")){ + log_error("netlist_modifier", "A file called 'generated' in the project directory exists but it is expected to be a directory!"); + return false; + } + std::filesystem::create_directories(project_dir_path/"generated"); + + std::filesystem::copy(gNetlist->get_gate_library()->get_path(), project_dir_path/"generated/gatelib_obfuscated.hgl"); + } - // no writer for .v ???? - netlist_writer_manager::write(modified_netlist_pointer, "/home/ole/Documents/MPI/hal_project_for_testing/modified_netlist_pointer.v"); + + GateLibrary* lib = gate_library_manager::load(project_dir_path/"generated/gatelib_obfuscated.hgl");*/ - // crashes when executed - // gNetlist = (NetlistModifierPlugin::modified_netlist_pointer->copy()).get().get(); + std::vector gates = guiAPI->getSelectedGates(); - // std::cout << gNetlist->get_gates().size() << std::endl; + for (Gate* gate : gates) + { + if (!replace_gate_in_netlist(gNetlist, gate)) + { + return false; + } + } return true; } + bool NetlistModifierPlugin::save() + { + ProjectManager* pm = ProjectManager::instance(); + std::filesystem::path project_dir_path(pm->get_project_directory().string()); + if (std::filesystem::exists(project_dir_path / "generated") && !std::filesystem::is_directory(project_dir_path / "generated")) + { + log_error("netlist_modifier", "A file called 'generated' in the project directory exists but it is expected to be a directory!"); + return false; + } + if (!std::filesystem::exists(project_dir_path / "generated")) + { + std::filesystem::create_directories(project_dir_path / "generated"); + } + netlist_writer_manager::write(gNetlist, project_dir_path / "generated/generated_netlist_obfuscated.v"); + std::filesystem::copy(gNetlist->get_gate_library()->get_path(), project_dir_path / "generated/generated_gatelib_obfuscated.hgl"); + return true; + } + GuiExtensionNetlistModifier::GuiExtensionNetlistModifier() + { + m_parameter.push_back(PluginParameter(PluginParameter::PushButton, "modify_in_place", "Modify selected gates in place")); + m_parameter.push_back(PluginParameter(PluginParameter::PushButton, "save", "Save")); + } + std::vector GuiExtensionNetlistModifier::get_parameter() const + { + return m_parameter; + } + void GuiExtensionNetlistModifier::set_parameter(const std::vector& params) + { + m_parameter = params; + bool modify_in_place = false; + bool save = false; - - GuiExtensionNetlistModifier::GuiExtensionNetlistModifier() - { - m_parameter.push_back(PluginParameter(PluginParameter::PushButton,"modify","Modify and save")); - } - - std::vector GuiExtensionNetlistModifier::get_parameter() const - { - return m_parameter; - } - - void GuiExtensionNetlistModifier::set_parameter(const std::vector& params) - { - m_parameter = params; - bool modify_save = false; - for (PluginParameter par : m_parameter) - { - if(par.get_tagname()=="modify" && par.get_value() == "clicked") - modify_save = true; - } - if (modify_save && m_parent ) - { - m_parent->create_modified_netlist(); - } - } - - -} // namespace hal \ No newline at end of file + for (PluginParameter par : m_parameter) + { + if (par.get_tagname() == "modify_in_place" && par.get_value() == "clicked") + { + modify_in_place = true; + } + else if (par.get_tagname() == "save" && par.get_value() == "clicked") + { + save = true; + } + } + if (modify_in_place && m_parent) + { + m_parent->modify_in_place(); + } + else if (save && m_parent) + { + m_parent->save(); + } + } +} // namespace hal \ No newline at end of file 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 f5fef599b43..514f557edfe 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,8 +1,7 @@ #pragma once -#include "hal_core/plugin_system/plugin_interface_base.h" #include "hal_core/plugin_system/gui_extension_interface.h" - +#include "hal_core/plugin_system/plugin_interface_base.h" namespace hal { @@ -11,10 +10,11 @@ namespace hal class PLUGIN_API NetlistSimulatorStudyPlugin : public BasePluginInterface { - GuiExtensionNetlistSimulatorStudy* m_gui_extension; + GuiExtensionNetlistSimulatorStudy* m_gui_extension; std::unique_ptr m_simul_controller; + public: - std::unique_ptr m_original_netlist; + std::unique_ptr m_original_netlist; NetlistSimulatorStudyPlugin(); std::string get_name() const override; @@ -29,7 +29,6 @@ namespace hal std::set get_dependencies() const override; bool simulate(std::filesystem::path sim_input, std::vector probes); - }; class GuiExtensionNetlistSimulatorStudy : public GuiExtensionInterface @@ -44,6 +43,5 @@ namespace hal std::vector get_parameter() const override; void set_parameter(const std::vector& params) override; - }; } // 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 57f3c306f21..c749403f649 100644 --- a/plugins/netlist_simulator_study/src/netlist_simulator_study.cpp +++ b/plugins/netlist_simulator_study/src/netlist_simulator_study.cpp @@ -3,10 +3,12 @@ #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 @@ -16,6 +18,8 @@ namespace hal { + extern Netlist* gNetlist; + extern std::unique_ptr create_plugin_instance() { return std::make_unique(); @@ -38,27 +42,9 @@ namespace hal void NetlistSimulatorStudyPlugin::on_load() { - // TODO: make this more user friendly - std::string netlist_path = "/home/ole/Documents/MPI/hal_project_for_testing/fulladderStructural_netlist.v"; - std::string gatelib_path = "/home/ole/Documents/programs/hal/build/share/hal/gate_libraries/NangateOpenCellLibrary.hgl"; - - if (std::filesystem::exists(netlist_path) && std::filesystem::exists(gatelib_path)) - { - m_original_netlist = netlist_factory::load_netlist(netlist_path, gatelib_path); - } - else - { - m_original_netlist = nullptr; - } - - std::cout << m_original_netlist.get() << std::endl; - - if (m_original_netlist) - { - m_gui_extension = new GuiExtensionNetlistSimulatorStudy; - m_gui_extension->m_parent = this; - m_extensions.push_back(m_gui_extension); - } + m_gui_extension = new GuiExtensionNetlistSimulatorStudy; + m_gui_extension->m_parent = this; + m_extensions.push_back(m_gui_extension); } void NetlistSimulatorStudyPlugin::on_unload() @@ -84,16 +70,30 @@ namespace hal bool NetlistSimulatorStudyPlugin::simulate(std::filesystem::path sim_input, std::vector probes) { - if (!m_original_netlist) return false; + // read the original netlist + ProjectManager* pm = ProjectManager::instance(); + std::filesystem::path project_dir_path(pm->get_project_directory().string()); + + if (!std::filesystem::exists(project_dir_path / "original/original.v")) + { + log_error("netlist_simulator_study", "Original netlist file is missing!"); + return false; + } + + m_original_netlist = netlist_factory::load_netlist(project_dir_path / "original/original.v", gNetlist->get_gate_library()->get_path()); + + if (!std::filesystem::exists(sim_input)) + { + return false; + } - 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") @@ -105,6 +105,8 @@ namespace hal 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) { @@ -170,6 +172,32 @@ namespace hal bool valid_inputs = true; + // read settings file and values + ProjectManager* pm = ProjectManager::instance(); + std::filesystem::path project_dir_path(pm->get_project_directory().string()); + + if (!std::filesystem::exists(project_dir_path / "original/settings.ini")) + { + log_error("netlist_simulator_study", "Settings file is missing!"); + return; + } + + QSettings my_settings(QString::fromStdString(project_dir_path / "original/settings.ini"), QSettings::IniFormat); + + 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() == "net_picker" && par.get_value() == "clicked") @@ -184,48 +212,64 @@ namespace hal if (sim_input == "") { - valid_inputs = false; + return; } std::vector nets = guiAPI->getSelectedNets(); - // get all the selected wires that are not global in or out - for (Net* net : nets) + // select only the allowed nets from the selected nets + if (PROBE_TYPE) { - if (net->is_global_input_net() || net->is_global_output_net()) + // t probe model (n arbitrary probes) + for (Net* net : nets) { - continue; + 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_destinations(); - bool dff_as_source = false; + std::vector sources = net->get_sources(); + bool dff_as_source = false; - for(Endpoint* source: sources){ - if(source->get_gate()->get_type()->get_name().find("DFF") != std::string::npos){ - dff_as_source = true; - break; + for (Endpoint* source : sources) + { + if (source->get_gate()->get_type()->get_name().find("DFF") != std::string::npos) + { + dff_as_source = true; + break; + } } - } - if (!dff_as_source) - { - continue; - }*/ - + if (!dff_as_source) + { + continue; + } - probes.push_back(net); + probes.push_back(net); + } } - // only let the user to select at most 5 probes - const u8 MAX_PROBES = 5; - std::vector probes_final_selection; + // verify that only MAX_PROBES are selected or select a random subset if checkbox is checked if (probes.size() > MAX_PROBES) { if (!net_picker_checkbox) { - valid_inputs = false; + log_error("netlist_simulator_study", "You selected more than " + std::to_string(MAX_PROBES) + " probes"); + return; } else { @@ -254,7 +298,8 @@ namespace hal } } - for (Net* net : m_parent->m_original_netlist.get()->get_nets()) + // 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()) {