HAL  v4.5.0-254-g8f9f6a423
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
plugin_xilinx_toolbox.cpp
Go to the documentation of this file.
2 
8 
9 #include <unordered_set>
10 
11 namespace hal
12 {
14  {
15  m_extensions.push_back(new GuiExtensionXilinxToolbox());
16  }
17 
18  extern std::unique_ptr<BasePluginInterface> create_plugin_instance()
19  {
20  return std::make_unique<XilinxToolboxPlugin>();
21  }
22 
23  std::string XilinxToolboxPlugin::get_name() const
24  {
25  return std::string("xilinx_toolbox");
26  }
27 
29  {
30  return std::string("0.1");
31  }
32 
34  {
35  return "A collection of functions specifically designed to operate on Xilinx FPGA netlists.";
36  }
37 
38  std::set<std::string> XilinxToolboxPlugin::get_dependencies() const
39  {
40  return {};
41  }
42 
43  std::vector<PluginParameter> GuiExtensionXilinxToolbox::get_parameter() const
44  {
45  return {
46  {PluginParameter::Boolean, "split_luts", "Split all LUT6_2 gates", mSplitLuts ? "true" : "false"},
47  {PluginParameter::Boolean, "split_shift_registers", "Split all shift register gates", mSplitShiftRegisters ? "true" : "false"},
48  {PluginParameter::PushButton, "execute", "Execute"},
49  };
50  }
51 
52  void GuiExtensionXilinxToolbox::set_parameter(const std::vector<PluginParameter>& params)
53  {
54  for (const auto& p : params)
55  {
56  if (p.get_tagname() == "split_luts")
57  {
58  mSplitLuts = (p.get_value() == "true");
59  }
60  else if (p.get_tagname() == "split_shift_registers")
61  {
62  mSplitShiftRegisters = (p.get_value() == "true");
63  }
64  }
65  }
66 
67  namespace
68  {
73  std::vector<Gate*> gates_from_selection(Netlist* nl, const std::vector<u32>& mods, const std::vector<u32>& gats)
74  {
75  std::vector<Gate*> res;
76  std::unordered_set<Gate*> seen;
77 
78  const auto collect = [&res, &seen](Gate* g) {
79  if (g != nullptr && seen.insert(g).second)
80  {
81  res.push_back(g);
82  }
83  };
84 
85  for (u32 id : gats)
86  {
87  collect(nl->get_gate_by_id(id));
88  }
89 
90  for (u32 id : mods)
91  {
92  if (const Module* m = nl->get_module_by_id(id); m != nullptr)
93  {
94  for (Gate* g : m->get_gates(nullptr, true))
95  {
96  collect(g);
97  }
98  }
99  }
100 
101  return res;
102  }
103  } // namespace
104 
105  std::vector<ContextMenuContribution> GuiExtensionXilinxToolbox::get_context_contribution(const Netlist*, const std::vector<u32>& mods, const std::vector<u32>& gats, const std::vector<u32>& nets)
106  {
107  std::vector<ContextMenuContribution> retval;
108 
109  const auto add = [this, &retval](const std::string& tag, const std::string& entry) {
111  cmc.mContributer = this;
112  cmc.mTagname = tag;
113  cmc.mEntry = entry;
114  retval.push_back(cmc);
115  };
116 
117  // a selection is what the user is pointing at, so do not offer to run on the entire netlist next to it
118  if (!mods.empty() || !gats.empty())
119  {
120  add("split_luts_selection", "Split LUTs of selection");
121  add("split_shift_registers_selection", "Split shift registers of selection");
122  }
123  else if (!nets.empty())
124  {
125  add("remove_no_load_wires_selection", "Remove no load wires of selection");
126  }
127  else
128  {
129  add("split_luts_netlist", "Split LUTs of netlist");
130  add("split_shift_registers_netlist", "Split shift registers of netlist");
131  add("remove_no_load_wires_netlist", "Remove no load wires of netlist");
132  }
133 
134  return retval;
135  }
136 
137  void GuiExtensionXilinxToolbox::execute_function(std::string tag, Netlist* nl, const std::vector<u32>& mods, const std::vector<u32>& gats, const std::vector<u32>& nets)
138  {
139  if (nl == nullptr)
140  {
141  log_warning("xilinx_toolbox", "cannot run preprocessing: no netlist loaded.");
142  return;
143  }
144 
145  // deleting or replacing a gate makes the GUI re-layout its graph views, which would otherwise happen once
146  // per gate and dominate the runtime of the preprocessing itself
147  const xilinx_toolbox::GuiLayoutLocker layout_locker;
148 
149  // an empty scope makes the preprocessing functions consider the entire netlist
150  std::vector<Gate*> scope;
151  if (tag == "split_luts_selection" || tag == "split_shift_registers_selection")
152  {
153  scope = gates_from_selection(nl, mods, gats);
154  if (scope.empty())
155  {
156  log_warning("xilinx_toolbox", "cannot run preprocessing on the selection: no gates selected.");
157  return;
158  }
159  }
160 
161  if (tag == "execute")
162  {
163  // the plugin parameter dialog runs the chosen steps on the entire netlist
164  if (mSplitLuts)
165  {
166  if (const auto res = xilinx_toolbox::split_luts(nl); res.is_error())
167  {
168  log_error("xilinx_toolbox", "failed to split LUTs: {}", res.get_error().get());
169  }
170  }
171  if (mSplitShiftRegisters)
172  {
173  if (const auto res = xilinx_toolbox::split_shift_registers(nl); res.is_error())
174  {
175  log_error("xilinx_toolbox", "failed to split shift registers: {}", res.get_error().get());
176  }
177  }
178  }
179  else if (tag == "split_luts_selection" || tag == "split_luts_netlist")
180  {
181  if (const auto res = xilinx_toolbox::split_luts(nl, scope); res.is_error())
182  {
183  log_error("xilinx_toolbox", "failed to split LUTs: {}", res.get_error().get());
184  }
185  else
186  {
187  log_info("xilinx_toolbox", "split {} LUTs.", res.get());
188  }
189  }
190  else if (tag == "split_shift_registers_selection" || tag == "split_shift_registers_netlist")
191  {
192  if (const auto res = xilinx_toolbox::split_shift_registers(nl, scope); res.is_error())
193  {
194  log_error("xilinx_toolbox", "failed to split shift registers: {}", res.get_error().get());
195  }
196  else
197  {
198  log_info("xilinx_toolbox", "split {} shift registers.", res.get());
199  }
200  }
201  else if (tag == "remove_no_load_wires_selection" || tag == "remove_no_load_wires_netlist")
202  {
203  std::vector<Net*> net_scope;
204  if (tag == "remove_no_load_wires_selection")
205  {
206  for (u32 id : nets)
207  {
208  if (Net* n = nl->get_net_by_id(id); n != nullptr)
209  {
210  net_scope.push_back(n);
211  }
212  }
213  if (net_scope.empty())
214  {
215  log_warning("xilinx_toolbox", "cannot remove no load wires of the selection: no nets selected.");
216  return;
217  }
218  }
219 
220  if (const auto res = xilinx_toolbox::remove_no_load_wires(nl, net_scope); res.is_error())
221  {
222  log_error("xilinx_toolbox", "failed to remove no load wires: {}", res.get_error().get());
223  }
224  else
225  {
226  log_info("xilinx_toolbox", "removed {} no load wires.", res.get());
227  }
228  }
229  else
230  {
231  log_warning("xilinx_toolbox", "unknown context menu tag '{}'.", tag);
232  }
233  }
234 } // namespace hal
std::vector< AbstractExtensionInterface * > m_extensions
Definition: gate.h:59
GUI extension interface for the Xilinx toolbox plugin.
std::vector< ContextMenuContribution > get_context_contribution(const Netlist *nl, const std::vector< u32 > &mods, const std::vector< u32 > &gats, const std::vector< u32 > &nets) override
Get the context menu entries contributed for the given selection.
void set_parameter(const std::vector< PluginParameter > &params) override
Set the parameters chosen in the plugin parameter dialog.
void execute_function(std::string tag, Netlist *nl, const std::vector< u32 > &mods, const std::vector< u32 > &gats, const std::vector< u32 > &nets) override
Execute the context menu entry identified by the given tag.
std::vector< PluginParameter > get_parameter() const override
Get the parameters shown in the plugin parameter dialog.
Definition: net.h:58
Gate * get_gate_by_id(const u32 gate_id) const
Definition: netlist.cpp:195
Module * get_module_by_id(u32 module_id) const
Definition: netlist.cpp:615
Net * get_net_by_id(u32 net_id) const
Definition: netlist.cpp:355
XilinxToolboxPlugin()
Constructor for XilinxToolboxPlugin that registers the GUI extension.
std::string get_name() const override
Get the name of the plugin.
std::string get_version() const override
Get the version of the plugin.
std::set< std::string > get_dependencies() const override
Get the plugin dependencies.
std::string get_description() const override
Get a short description of the plugin.
Suppresses layout updates of the GUI for as long as the object exists.
uint32_t u32
Definition: defines.h:41
#define log_error(channel,...)
Definition: log.h:78
#define log_info(channel,...)
Definition: log.h:70
#define log_warning(channel,...)
Definition: log.h:76
Result< u32 > remove_no_load_wires(Netlist *nl, const std::vector< Net * > &nets={})
Remove the "no load wire" nets that Vivado writes for unused output pins.
Result< u32 > split_shift_registers(const std::vector< Gate * > &gates, bool create_module=false)
Split a set of shift register primitives into equivalent FDCE flip-flop chains.
Result< u32 > split_luts(const std::vector< Gate * > &gates, bool create_module=false)
Split a set of LUT6_2 gates into separate LUT gates.
Definition: defines.h:45
std::unique_ptr< BasePluginInterface > create_plugin_instance()
This file contains all functions related to the HAL plugin API.
This file contains functions specifically designed to preprocess Xilinx FPGA netlists.
GuiExtensionInterface * mContributer
This file contains a helper that suppresses layout updates of the GUI.