diff --git a/plugins/netlist_modifier/include/netlist_modifier/netlist_modifier.h b/plugins/netlist_modifier/include/netlist_modifier/netlist_modifier.h index 188e36cf96a..2ada3b47769 100644 --- a/plugins/netlist_modifier/include/netlist_modifier/netlist_modifier.h +++ b/plugins/netlist_modifier/include/netlist_modifier/netlist_modifier.h @@ -13,6 +13,9 @@ namespace hal { GuiExtensionNetlistModifier* m_gui_extension; + 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(); public: std::string get_name() const override; std::string get_version() const override; @@ -42,4 +45,4 @@ namespace hal void set_parameter(const std::vector& params) override; }; -} // namespace hal \ No newline at end of file +} // namespace hal diff --git a/plugins/netlist_modifier/src/netlist_modifier.cpp b/plugins/netlist_modifier/src/netlist_modifier.cpp index 717df1e0343..788359e05df 100644 --- a/plugins/netlist_modifier/src/netlist_modifier.cpp +++ b/plugins/netlist_modifier/src/netlist_modifier.cpp @@ -4,6 +4,7 @@ #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/gate_library/gate_library_writer/gate_library_writer_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" @@ -17,12 +18,19 @@ #include #include +#include +#include +#include +#include #define SECRET_PASSWORD "test12345" namespace hal { + const char* OBFUSCATED = "_obfuscated"; + const char* GATE_LIB_TAG = "gate_library"; + extern Netlist* gNetlist; extern std::unique_ptr create_plugin_instance() @@ -62,6 +70,7 @@ namespace hal std::set retval; retval.insert("hal_gui"); retval.insert("verilog_writer"); + retval.insert("hgl_writer"); return retval; } @@ -69,17 +78,25 @@ namespace hal { } - bool replace_gate_in_netlist(Netlist* netlist, Gate* gate) + 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"; + if (num_io) + retval += "_" + std::to_string(num_io) + "IO"; + return retval; + } + + bool NetlistModifierPlugin::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(); - 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"); + GateType* new_gate_type = netlist->get_gate_library()->get_gate_type_by_name(obfuscated_gate_name(num_of_in,num_of_out)); 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"); + log_error("netlist_modifier", "No gatetype called '{}' in gatelib", obfuscated_gate_name(num_of_in,num_of_out)); return false; } @@ -104,17 +121,17 @@ namespace hal Gate* new_gate = netlist->create_gate(gate_id, new_gate_type, gate_name); // add old connections - int counter = 1; + int counter = 0; for (Net* net : in_nets) { - net->add_destination(new_gate, "IN_" + std::to_string(counter)); + net->add_destination(new_gate, "I" + std::to_string(counter)); counter++; } - counter = 1; + counter = 0; for (Net* net : out_nets) { - net->add_source(new_gate, "OUT_" + std::to_string(counter)); + net->add_source(new_gate, "O" + std::to_string(counter)); counter++; } @@ -207,11 +224,112 @@ max_probes=5)"; return true; } + bool NetlistModifierPlugin::modify_gatelibrary() + { + ProjectManager* pm = ProjectManager::instance(); + + std::filesystem::path projFilePath(pm->get_project_directory()); + if (projFilePath.empty() || !std::filesystem::exists(projFilePath)) + { + log_warning("netlist_modifier", "Cannot access project directory '{}'.", projFilePath.string()); + return false; + } + projFilePath.append(ProjectManager::s_project_file); + + // get location of current gate library from project file + FILE* fp = fopen(projFilePath.string().c_str(), "rb"); + if (fp == NULL) + { + log_warning("netlist_modifier", "Cannot open project file '{} for reading'.", projFilePath.string()); + return false; + } + + char buffer[65536]; + rapidjson::FileReadStream frs(fp, buffer, sizeof(buffer)); + rapidjson::Document doc; + doc.ParseStream<0, rapidjson::UTF8<>, rapidjson::FileReadStream>(frs); + fclose(fp); + + std::filesystem::path modifiedGateLibraryPath; + if (doc.HasMember(GATE_LIB_TAG)) + { + std::filesystem::path originalGateLibraryPath = doc[GATE_LIB_TAG].GetString(); + if (originalGateLibraryPath.stem().string().find(OBFUSCATED) != std::string::npos) + { + // using already gate library with obfuscated gates + return true; + } + // generate new name for gate library with obfuscated gates + modifiedGateLibraryPath = pm->get_project_directory().get_filename(originalGateLibraryPath.stem().string() + OBFUSCATED + ".hgl"); + } + 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 + } + + // yes, we know what we are doing when casting away const ;-) + // Modifying attibutes of a GateType in HAL while netlist is loaded might produce unpredictable results, + // thus GateLibrary is declared const. However, we are only adding GateType's, this should be safe. + GateLibrary* gl = const_cast(gNetlist->get_gate_library()); + + // map gate type categories by number of pins + std::unordered_map pinCountMap; + for (auto const& [key, gt] : gl->get_gate_types()) + { + int count[5] = {0, 0, 0, 0, 0}; + for (const GatePin* gp : gt->get_pins()) + { + count[(int)gp->get_direction()]++; + } + u32 pinCount = (count[1] & 0x3FF) | ((count[2] & 0x3FF) << 10) | ((count[3] & 0x3FF) << 20); + ++pinCountMap[pinCount]; + } + + // create dummy gate types with appropriate number of pins + 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); + } + + if (!gate_library_writer_manager::write(gl, modifiedGateLibraryPath)) + { + log_warning("netlist_modifier", "cannot write modified gate library to file'{}'.", modifiedGateLibraryPath.string()); + return false; + } + + // write modified project file + rapidjson::Value::MemberIterator gatelibMemberIterator = doc.FindMember(GATE_LIB_TAG); + gatelibMemberIterator->value.SetString(modifiedGateLibraryPath.filename().string().c_str(), doc.GetAllocator()); + + FILE* of = fopen(projFilePath.string().c_str(), "wb"); + if (of == NULL) + { + log_warning("netlist_modifier", "cannot open project file '{}' for rewrite.", projFilePath.string()); + return false; + } + rapidjson::FileWriteStream fws(of, buffer, sizeof(buffer)); + rapidjson::Writer writer(fws); + doc.Accept(writer); + fclose(of); + + return true; + } + bool NetlistModifierPlugin::modify_in_place() { - GuiApi* guiAPI = new GuiApi(); + if (!modify_gatelibrary()) return false; - std::vector gates = guiAPI->getSelectedGates(); + std::vector gates = GuiApi().getSelectedGates(); // save original netlist if it does not contain any UNKNOWN gates bool contains_unknown = false; @@ -297,4 +415,4 @@ max_probes=5)"; m_parent->save(); } } -} // namespace hal \ No newline at end of file +} // namespace hal