17 for (
unsigned char c : p->
get_name())
19 if (c >=
'0' && c <=
'9')
21 digits +=
static_cast<char>(c);
24 return static_cast<u32>(std::stoull(digits));
29 std::string srl_cascade_pin(
const std::string& type_name)
31 if (type_name ==
"SRLC16E")
35 if (type_name ==
"SRLC32E")
42 bool is_srl_type(
const std::string& type_name)
44 return type_name ==
"SRL16E" || type_name ==
"SRL16" || type_name ==
"SRLC16E" || type_name ==
"SRLC32E";
50 namespace xilinx_toolbox
59 std::vector<Gate*> gates_in_scope(
const Netlist* nl,
const std::vector<Gate*>& gates,
const std::function<
bool(
const Gate*)>& type_filter)
63 return nl->get_gates(type_filter);
66 std::vector<Gate*> res;
82 return ERR(
"gate '" + g->
get_name() +
"' with ID " + std::to_string(g->
get_id()) +
" is not of type LUT6_2");
93 Module* target_mod =
nullptr;
108 return ERR(
"LUT6_2 gate type has no LUT component");
112 if (o5 !=
nullptr && o5->get_num_of_destinations() > 0)
115 if (init_O5_res.is_error())
117 log_warning(
"xilinx_toolbox",
"could not get INIT string for O5 of gate '{}' with ID {}, skipping O5 split.", g->
get_name(), g->
get_id());
121 const auto init_O5 = init_O5_res.get();
123 lut5->
set_data(
"xilinx_preprocessing_information",
"original_init",
"string", init_O5);
125 if (lc_lut5t ==
nullptr || lc_lut5t->set_init_string(lut5,
"O", init_O5).is_error())
127 log_warning(
"xilinx_toolbox",
"could not set INIT string of gate '{}' with ID {}.", lut5->get_name(), lut5->get_id());
132 if (target_mod !=
nullptr)
141 if (in_ep->get_pin()->get_name() ==
"I5")
146 in_ep->get_net()->add_destination(lut5, in_ep->get_pin()->get_name());
149 o5->add_source(lut5,
"O");
154 if (o6 !=
nullptr && o6->get_num_of_destinations() > 0)
156 const auto init_O6_res = lc_g->get_init_string(g,
"O6");
157 if (init_O6_res.is_error())
159 return ERR(
"could not get O6 INIT string of gate '" + g->
get_name() +
"' with ID " + std::to_string(g->
get_id()));
163 const auto init_O6 = init_O6_res.get();
165 lut6->
set_data(
"xilinx_preprocessing_information",
"original_init",
"string", init_O6);
168 if (lc_lut6t ==
nullptr || lc_lut6t->set_init_string(lut6,
"O", init_O6).is_error())
170 log_warning(
"xilinx_toolbox",
"could not set INIT string of gate '{}' with ID {}.", lut6->get_name(), lut6->get_id());
175 if (target_mod !=
nullptr)
182 in_ep->get_net()->add_destination(lut6, in_ep->get_pin()->get_name());
185 o6->add_source(lut6,
"O");
193 return ERR(
"failed to delete gate '" + g->
get_name() +
"' with ID " + std::to_string(g->
get_id()));
202 for (
auto* g : gates)
204 if (
auto res =
split_lut(g, create_module); res.is_error())
206 log_warning(
"xilinx_toolbox",
"skipping gate '{}' with ID {}: {}", g->get_name(), g->get_id(), res.get_error().get());
213 log_info(
"xilinx_toolbox",
"split {} of {} LUT6_2 gates into LUT6 and LUT5 gates", count, gates.size());
219 return split_luts(gates_in_scope(nl, gates, [](
const Gate* g) {
return g->
get_type()->get_name() ==
"LUT6_2"; }), create_module);
225 if (!is_srl_type(type_name))
227 return ERR(
"gate '" + g->
get_name() +
"' with ID " + std::to_string(g->
get_id()) +
" is not a supported shift register type (SRL16, SRL16E, SRLC16E, SRLC32E)");
232 if (ff_gt ==
nullptr)
234 return ERR(
"could not find gate type 'FDCE' in gate library");
240 const u32 expected_ctrl = (type_name ==
"SRLC32E") ? 5u : 4u;
241 if (ctrl_pins.size() != expected_ctrl)
243 return ERR(
"gate '" + g->
get_name() +
"' with ID " + std::to_string(g->
get_id()) +
" has " + std::to_string(ctrl_pins.size()) +
" control pins, expected "
244 + std::to_string(expected_ctrl));
247 std::sort(ctrl_pins.begin(), ctrl_pins.end(), [](
const GatePin* a,
const GatePin* b) { return srl_addr_pin_index(a) < srl_addr_pin_index(b); });
251 u32 select_value = 0;
252 for (
u32 i = 0; i < ctrl_pins.size(); i++)
257 return ERR(
"control pin '" + ctrl_pins[i]->get_name() +
"' of gate '" + g->
get_name() +
"' with ID " + std::to_string(g->
get_id()) +
" has no connected net");
261 return ERR(
"control pin '" + ctrl_pins[i]->get_name() +
"' of gate '" + g->
get_name() +
"' with ID " + std::to_string(g->
get_id()) +
" is not driven by a constant (GND/VCC) net");
265 select_value |= (1u << i);
271 if (clk_pins.size() != 1)
273 return ERR(
"gate '" + g->
get_name() +
"' with ID " + std::to_string(g->
get_id()) +
" has " + std::to_string(clk_pins.size()) +
" clock pins, expected 1");
277 if (en_pins.size() != 1)
279 return ERR(
"gate '" + g->
get_name() +
"' with ID " + std::to_string(g->
get_id()) +
" has " + std::to_string(en_pins.size()) +
" enable pins, expected 1");
283 if (data_pins.size() != 1)
285 return ERR(
"gate '" + g->
get_name() +
"' with ID " + std::to_string(g->
get_id()) +
" has " + std::to_string(data_pins.size()) +
" data pins, expected 1");
292 if (clk_in ==
nullptr)
294 return ERR(
"no clock input connected to gate '" + g->
get_name() +
"' with ID " + std::to_string(g->
get_id()));
296 if (enable_in ==
nullptr)
298 return ERR(
"no enable input connected to gate '" + g->
get_name() +
"' with ID " + std::to_string(g->
get_id()));
300 if (data_in ==
nullptr)
302 return ERR(
"no data input connected to gate '" + g->
get_name() +
"' with ID " + std::to_string(g->
get_id()));
306 const std::string casc_pin = srl_cascade_pin(type_name);
313 if (state_out ==
nullptr && !cascade_used)
315 return ERR(
"no output connected to gate '" + g->
get_name() +
"' with ID " + std::to_string(g->
get_id()));
320 const u32 max_depth = (1u << ctrl_pins.size()) - 1u;
321 const u32 register_size = cascade_used ? max_depth : select_value;
327 Module* target_mod =
nullptr;
334 target_mod = parent_mod;
341 const bool has_clk_inv = g->
has_parameter(
"IS_CLK_INVERTED");
342 const std::string clk_inv_val = has_clk_inv ? g->
get_parameter_value(
"IS_CLK_INVERTED").get() :
"";
354 log_warning(
"xilinx_toolbox",
"could not parse INIT of gate '{}' with ID {}, skipping INIT copy", g->
get_name(), g->
get_id());
359 std::vector<Net*> chain_nets;
361 for (
u32 i = 0; i <= register_size; i++)
363 const std::string ff_name = g->
get_name() +
"_split_ff_" + std::to_string(i);
366 if (target_mod !=
nullptr)
373 if (
auto decl =
ff->get_type()->get_parameter(
"INIT"); decl.is_ok())
375 const std::string bit_val = ((init_bits >> i) & 1u) ?
"0x1" :
"0x0";
376 if (
ff->set_parameter(decl.get(), bit_val).is_error())
378 log_warning(
"xilinx_toolbox",
"could not copy INIT bit {} to FF '{}' with ID {}", i,
ff->get_name(),
ff->get_id());
384 if (
auto decl =
ff->get_type()->get_parameter(
"IS_C_INVERTED"); decl.is_ok())
386 if (
ff->set_parameter(decl.get(), clk_inv_val).is_error())
388 log_warning(
"xilinx_toolbox",
"could not copy IS_CLK_INVERTED to IS_C_INVERTED on FF '{}' with ID {}",
ff->get_name(),
ff->get_id());
396 (i == 0 ? data_in : chain_nets.back())->add_destination(
ff,
"D");
398 const bool is_q_stage = (state_out !=
nullptr && i == select_value);
399 const bool is_cascade_stage = (cascade_used && i == register_size);
404 if (is_cascade_stage)
409 std::vector<std::pair<Gate*, std::string>> casc_consumers;
412 casc_consumers.emplace_back(ep->get_gate(), ep->get_pin()->get_name());
414 for (
const auto& [g, pin] : casc_consumers)
420 chain_nets.push_back(state_out);
422 else if (is_cascade_stage)
425 chain_nets.push_back(cascade_out);
431 chain_nets.push_back(
internal);
437 return ERR(
"failed to delete gate '" + g->
get_name() +
"' with ID " + std::to_string(g->
get_id()));
446 for (
Gate* g : gates)
450 log_warning(
"xilinx_toolbox",
"skipping gate '{}' with ID {}: {}", g->get_name(), g->get_id(), res.get_error().get());
457 log_info(
"xilinx_toolbox",
"split {} of {} shift register gates into FDE flip-flop chains", count, gates.size());
470 return ERR(
"cannot remove no load wires: netlist is a nullptr");
476 const auto is_no_load_wire = [](
const Net* n) {
477 const std::string&
name = n->get_name();
478 const std::string prefix =
"NLW_";
479 const std::string suffix =
"_UNCONNECTED";
481 if (
name.compare(0, prefix.size(), prefix) != 0 &&
name.find(
"/" + prefix) == std::string::npos)
486 std::string::size_type end =
name.size();
487 if (end > 0 && (
name[end - 1] ==
')' ||
name[end - 1] ==
']'))
489 const auto open =
name.find_last_of(
"([");
490 if (open == std::string::npos || open + 1 >= end - 1 ||
name.find_first_not_of(
"0123456789", open + 1) != end - 1)
497 return end > prefix.size() + suffix.size() &&
name.compare(end - suffix.size(), suffix.size(), suffix) == 0;
500 std::vector<Net*> to_delete;
501 for (
Net* n : nets.empty() ? nl->
get_nets() : nets)
503 if (n ==
nullptr || n->get_netlist() != nl)
505 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()));
508 if (is_no_load_wire(n) && n->get_num_of_destinations() == 0 && !n->is_global_output_net())
510 to_delete.push_back(n);
514 u32 deleted_nets = 0;
515 for (
Net* n : to_delete)
517 const std::string
name = n->get_name();
518 const u32 id = n->get_id();
521 return ERR(
"cannot remove no load wires: failed to delete net '" +
name +
"' with ID " + std::to_string(
id));
526 log_info(
"xilinx_toolbox",
"removed {} no load wires", deleted_nets);
528 return OK(deleted_nets);
const std::string & get_name() const
PinDirection get_direction() const
Result< std::string > get_parameter_value(const std::string &name) const
bool has_parameter(const Parameter ¶m) const
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
Netlist * get_netlist() const
GateType * get_gate_type_by_name(const std::string &name) const
virtual ComponentType get_type() const =0
T * get_component_as(const std::function< bool(const GateTypeComponent *)> &filter=nullptr)
const std::string & get_name() const
T * get_component_as(const std::function< bool(const GateTypeComponent *)> &filter=nullptr) const
std::vector< GatePin * > get_pins(const std::function< bool(GatePin *)> &filter=nullptr) const
Result< std::string > get_init_string(const Gate *gate, const std::string &pin_name) const
bool is_top_module() const
bool assign_gate(Gate *gate)
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
std::vector< Endpoint * > get_destinations(const std::function< bool(Endpoint *ep)> &filter=nullptr) const
bool remove_destination(Gate *gate, const std::string &pin_name)
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
Module * create_module(const u32 module_id, const std::string &name, Module *parent, const std::vector< Gate * > &gates={})
#define log_info(channel,...)
#define log_warning(channel,...)