11 namespace xilinx_toolbox
20 std::vector<Gate*> gates_in_scope(
const Netlist* nl,
const std::vector<Gate*>& gates,
const std::function<
bool(
const Gate*)>& type_filter)
24 return nl->get_gates(type_filter);
27 std::vector<Gate*> res;
41 u32 deleted_gates = 0;
43 std::vector<Gate*> to_delete;
48 const auto lut6_2_gates = gates_in_scope(nl, gates, [](
const Gate* g) {
return g->
get_type()->get_name() ==
"LUT6_2"; });
50 for (
const auto& g : lut6_2_gates)
57 if (init_get_res.is_error())
59 log_warning(
"xilinx_toolbox",
"could not get INIT string of gate '{}' with ID {}, skipping this gate.", g->
get_name(), g->
get_id());
62 auto init = init_get_res.get().front();
63 if (init.length() != 16)
65 log_warning(
"xilinx_toolbox",
"INIT string '{}' has length {}, expected 16.", init, init.length());
70 if (o5 !=
nullptr && o5->get_num_of_destinations() > 0)
74 lut5->
set_data(
"xilinx_preprocessing_information",
"original_init",
"string", init);
76 auto init_O5 = init.substr(8, 8);
77 if (lut5->set_init_data({init_O5}).is_error())
79 log_warning(
"xilinx_toolbox",
"could not set INIT string of gate '{}' with ID {}, skipping this gate.", lut5->get_name(), lut5->get_id());
84 mod->assign_gate(lut5);
89 in_ep->get_net()->add_destination(lut5, in_ep->get_pin()->get_name());
93 o5->add_source(lut5,
"O");
96 if (o6 !=
nullptr && o6->get_num_of_destinations() > 0)
100 lut6->
set_data(
"xilinx_preprocessing_information",
"original_init",
"string", init);
102 if (lut6->set_init_data({init}).is_error())
104 log_warning(
"xilinx_toolbox",
"could not set INIT string of gate '{}' with ID {}, skipping this gate.", lut6->get_name(), lut6->get_id());
111 mod->assign_gate(lut6);
116 in_ep->get_net()->add_destination(lut6, in_ep->get_pin()->get_name());
120 o6->add_source(lut6,
"O");
122 to_delete.push_back(g);
125 for (
const auto& g : to_delete)
129 return ERR(
"Cannot split luts for netlist with ID " + std::to_string(nl->
get_id()) +
": Failed to delete gate " + g->
get_name() +
" with ID " + std::to_string(g->
get_id()));
137 log_info(
"xilinx_toolbox",
"split {} LUT6_2 gates into {} LUT6 and LUT5 gates", deleted_gates, new_gates);
138 return OK(deleted_gates);
143 u32 deleted_gates = 0;
145 std::vector<Gate*> to_delete;
148 if (ff_gt ==
nullptr)
150 return ERR(
"could not find gate type 'FDE' in gate library");
154 for (
const auto& gate : gates_in_scope(nl, gates, [](
const Gate* g) {
return g->
get_type()->get_name() ==
"SRL16E" || g->
get_type()->
get_name() ==
"SRLC32E"; }))
157 if (control_pins.size() != 4 && gate->get_type()->get_name() ==
"SRLC16E" || control_pins.size() != 5 && gate->get_type()->get_name() ==
"SRLC32E")
159 return ERR(
"invalid number of control pins");
162 if (gate->get_type()->get_name() ==
"SRL16E")
164 std::sort(control_pins.begin(), control_pins.end(), [](
const auto& p1,
const auto& p2) {
165 const u32 idx1 = std::stoull(p1->get_name().substr(1));
166 const u32 idx2 = std::stoull(p2->get_name().substr(1));
173 std::sort(control_pins.begin(), control_pins.end(), [](
const auto& p1,
const auto& p2) {
174 const u32 idx1 = std::stoull(p1->get_name().substr(2));
175 const u32 idx2 = std::stoull(p2->get_name().substr(2));
181 u32 select_value = 0;
182 for (
u32 idx = 0; idx < control_pins.size(); idx++)
184 const Net* cn = gate->get_fan_in_net(control_pins.at(idx));
188 log_warning(
"xilinx_toolbox",
"control net at pin '{}' of gate '{}' with ID {} is 'nullptr'", control_pins.at(idx)->get_name(), gate->get_name(), gate->get_id());
194 log_warning(
"xilinx_toolbox",
"control net at pin '{}' of gate '{}' with ID {} is not constant", control_pins.at(idx)->get_name(), gate->get_name(), gate->get_id());
198 select_value += (cn->
is_gnd_net() ? 0 : 1) << idx;
201 const auto clock_pins = gate->get_type()->get_pins([](
const auto& p) {
return (p->get_direction() ==
PinDirection::input) && (p->get_type() ==
PinType::clock); });
202 if (clock_pins.size() != 1)
204 return ERR(
"invalid number of input clock pins at shift register gate '" + gate->get_name() +
"' with ID " + std::to_string(gate->get_id()));
208 if (enable_pins.size() != 1)
210 return ERR(
"invalid number of input enable pins at shift register gate '" + gate->get_name() +
"' with ID " + std::to_string(gate->get_id()));
213 const auto data_pins = gate->get_type()->get_pins([](
const auto& p) {
return (p->get_direction() ==
PinDirection::input) && (p->get_type() ==
PinType::data); });
214 if (data_pins.size() != 1)
216 return ERR(
"invalid number of input data pins at shift register gate '" + gate->get_name() +
"' with ID " + std::to_string(gate->get_id()));
219 Net* clk_in = gate->get_fan_in_net(clock_pins.front());
220 Net* enable_in = gate->get_fan_in_net(enable_pins.front());
221 Net* data_in = gate->get_fan_in_net(data_pins.front());
222 Net* state_out =
nullptr;
223 Net* max_state_out =
nullptr;
225 if (gate->get_type()->get_name() ==
"SRLC32E")
227 state_out = gate->get_fan_out_net(
"Q");
228 max_state_out = gate->get_fan_out_net(
"Q31");
232 state_out = gate->get_fan_out_net(
"Q");
235 if (clk_in ==
nullptr)
237 return ERR(
"no clock input net connected to shift register gate '" + gate->get_name() +
"' with ID " + std::to_string(gate->get_id()));
240 if (enable_in ==
nullptr)
242 return ERR(
"no enable input net connected to shift register gate '" + gate->get_name() +
"' with ID " + std::to_string(gate->get_id()));
245 if (data_in ==
nullptr)
247 return ERR(
"no data input net connected to shift register gate '" + gate->get_name() +
"' with ID " + std::to_string(gate->get_id()));
250 if (state_out ==
nullptr && max_state_out ==
nullptr)
252 return ERR(
"no state output net connected to shift register gate '" + gate->get_name() +
"' with ID " + std::to_string(gate->get_id()));
255 u32 register_size = 0;
256 std::vector<Gate*> flip_flops;
257 std::vector<Net*> state_nets;
259 if (max_state_out !=
nullptr)
265 register_size = select_value;
268 for (
u32 ff_idx = 0; ff_idx <= register_size; ff_idx++)
270 const std::string ff_name = gate->get_name() +
"_split_ff_" + std::to_string(ff_idx);
275 if (
auto* mod = gate->get_module(); !mod->is_top_module())
277 mod->assign_gate(new_gate);
289 state_nets.back()->add_destination(new_gate,
"D");
292 if (ff_idx == select_value && state_out !=
nullptr)
295 state_nets.push_back(state_out);
297 else if (ff_idx == register_size && max_state_out !=
nullptr)
300 state_nets.push_back(max_state_out);
306 state_nets.push_back(new_net);
310 to_delete.push_back(gate);
313 for (
const auto& g : to_delete)
317 return ERR(
"Cannot split shift register primitives for netlist with ID " + std::to_string(nl->
get_id()) +
": Failed to delete gate " + g->
get_name() +
" with ID "
318 + std::to_string(g->
get_id()));
326 log_info(
"xilinx_toolbox",
"split {} SRL16E/SRLC32E gates into {} flip-flops", deleted_gates, new_gates);
328 return OK(deleted_gates);
335 return ERR(
"cannot remove no load wires: netlist is a nullptr");
341 const auto is_no_load_wire = [](
const Net* n) {
342 const std::string&
name = n->get_name();
343 const std::string prefix =
"NLW_";
344 const std::string suffix =
"_UNCONNECTED";
346 if (
name.compare(0, prefix.size(), prefix) != 0 &&
name.find(
"/" + prefix) == std::string::npos)
351 std::string::size_type end =
name.size();
352 if (end > 0 && (
name[end - 1] ==
')' ||
name[end - 1] ==
']'))
354 const auto open =
name.find_last_of(
"([");
355 if (open == std::string::npos || open + 1 >= end - 1 ||
name.find_first_not_of(
"0123456789", open + 1) != end - 1)
362 return end > prefix.size() + suffix.size() &&
name.compare(end - suffix.size(), suffix.size(), suffix) == 0;
365 std::vector<Net*> to_delete;
366 for (
Net* n : nets.empty() ? nl->
get_nets() : nets)
368 if (n ==
nullptr || n->get_netlist() != nl)
370 return ERR(
"cannot remove no load wires: a net of the scope does not belong to netlist with ID " + std::to_string(nl->
get_id()));
373 if (is_no_load_wire(n) && n->get_num_of_destinations() == 0 && !n->is_global_output_net())
375 to_delete.push_back(n);
379 u32 deleted_nets = 0;
380 for (
Net* n : to_delete)
382 const std::string
name = n->get_name();
383 const u32 id = n->get_id();
386 return ERR(
"cannot remove no load wires: failed to delete net '" +
name +
"' with ID " + std::to_string(
id));
391 log_info(
"xilinx_toolbox",
"removed {} no load wires", deleted_nets);
393 return OK(deleted_nets);
bool set_data(const std::string &category, const std::string &key, const std::string &data_type, const std::string &value, const bool log_with_info_level=false)
Net * get_fan_in_net(const std::string &pin_name) const
GateType * get_type() const
Net * get_fan_out_net(const std::string &pin_name) const
const std::string & get_name() const
Module * get_module() const
const std::vector< Endpoint * > & get_fan_in_endpoints() const
Result< std::vector< std::string > > get_init_data() const
GateType * get_gate_type_by_name(const std::string &name) const
const std::string & get_name() const
bool is_top_module() const
Endpoint * add_destination(Gate *gate, const std::string &pin_name)
Endpoint * add_source(Gate *gate, const std::string &pin_name)
u32 get_num_of_destinations(const std::function< bool(Endpoint *ep)> &filter=nullptr) const
bool delete_net(Net *net)
Net * create_net(const u32 net_id, const std::string &name)
bool delete_gate(Gate *gate)
Gate * create_gate(const u32 gate_id, GateType *gate_type, const std::string &name="", i32 x=-1, i32 y=-1)
const std::vector< Net * > & get_nets() const
const GateLibrary * get_gate_library() const
#define log_info(channel,...)
#define log_warning(channel,...)