vpr: Improve control over clock tracing
We now trace through black boxes only to input clock ports (instead of
all combinationally connected data ports). This allows users to specify
via the architecture file which pins are clock related.
For instance consider a clock buffer with an enable:
.subckt clkbufce \
in=clk3 \
enable=clk3_enable \
out=clk3_buf
Which would have a corresponding model:
<model name="clkbufce">
<input_ports>
<port name="in" combinational_sink_ports="out" is_clock="1"/>
<port name="enable" combinational_sink_ports="out"/>
</input_ports>
<output_ports>
<port name="out"/>
</output_ports>
</model>
and pb_type:
<pb_type name="clkbufce" blif_model="clkbufce" num_pb="1">
<clock name="in" num_pins="1"/>
<input name="enable" num_pins="1"/>
<output name="out" num_pins="1"/>
<delay_constant max="10e-12" in_port="clkbufce.in" out_port="clkbufce.out"/>
<delay_constant max="5e-12" in_port="clkbufce.enable" out_port="clkbufce.out"/>
</pb_type>
When tracing back the clock net 'clk3_buf', VPR will now look at the
upstream clock port ('in') and correctly identify the net 'clk3' as
being the same logical clock. Previously (when <clock>/is_clock were not
considered for this purpose) 'clk3_enable' would have also been (incorrectly)
detected as an upstream clock net.
diff --git a/vpr/src/base/atom_netlist_utils.cpp b/vpr/src/base/atom_netlist_utils.cpp
index 97ba56c..7621128 100644
--- a/vpr/src/base/atom_netlist_utils.cpp
+++ b/vpr/src/base/atom_netlist_utils.cpp
@@ -29,6 +29,9 @@
//Returns the set of input ports which are combinationally connected to output_port
std::vector<AtomPortId> find_combinationally_connected_input_ports(const AtomNetlist& netlist, AtomPortId output_port);
+//Returns the set of clock ports which are combinationally connected to output_port
+std::vector<AtomPortId> find_combinationally_connected_clock_ports(const AtomNetlist& netlist, AtomPortId output_port);
+
std::vector<AtomBlockId> identify_buffer_luts(const AtomNetlist& netlist);
bool is_buffer_lut(const AtomNetlist& netlist, const AtomBlockId blk);
bool is_removable_block(const AtomNetlist& netlist, const AtomBlockId blk, std::string* reason = nullptr);
@@ -658,6 +661,29 @@
return upstream_ports;
}
+std::vector<AtomPortId> find_combinationally_connected_clock_ports(const AtomNetlist& netlist, AtomPortId output_port) {
+ std::vector<AtomPortId> upstream_ports;
+
+ VTR_ASSERT(netlist.port_type(output_port) == PortType::OUTPUT);
+
+ std::string out_port_name = netlist.port_name(output_port);
+
+ AtomBlockId blk = netlist.port_block(output_port);
+
+ //Look through each block input port to find those which are combinationally connected to the output port
+ for (AtomPortId clock_port : netlist.block_clock_ports(blk)) {
+ const t_model_ports* clock_model_port = netlist.port_model(clock_port);
+ for (const std::string& sink_port_name : clock_model_port->combinational_sink_ports) {
+ if (sink_port_name == out_port_name) {
+ upstream_ports.push_back(clock_port);
+ }
+ }
+ }
+
+ return upstream_ports;
+}
+
+
void absorb_buffer_luts(AtomNetlist& netlist, int verbosity) {
//First we look through the netlist to find LUTs with identity logic functions
//we then remove those luts, replacing the net's they drove with the inputs to the
@@ -1371,8 +1397,18 @@
for (auto clk_net : prev_clock_nets) {
AtomPinId driver_pin = netlist.net_driver(clk_net);
AtomPortId driver_port = netlist.pin_port(driver_pin);
+ AtomBlockId driver_blk = netlist.port_block(driver_port);
- std::vector<AtomPortId> upstream_ports = find_combinationally_connected_input_ports(netlist, driver_port);
+ std::vector<AtomPortId> upstream_ports;
+
+ if (netlist.block_model(driver_blk)->name == std::string(".names")) {
+ //For .names we allow tracing back through data connections
+ //which allows us to traceback through white-box .names buffers
+ upstream_ports = find_combinationally_connected_input_ports(netlist, driver_port);
+ } else {
+ //For black boxes, we only trace back through inputs marked as clocks
+ upstream_ports = find_combinationally_connected_clock_ports(netlist, driver_port);
+ }
if (upstream_ports.empty()) {
//This net is a root net of a clock, keep it
@@ -1389,7 +1425,6 @@
VTR_ASSERT(upstream_net);
- AtomBlockId driver_blk = netlist.port_block(driver_port);
VTR_LOG_WARN("Assuming clocks may propagate through %s (%s) from pin %s to %s (assuming a non-inverting buffer).\n",
netlist.block_name(driver_blk).c_str(), netlist.block_model(driver_blk)->name,
netlist.pin_name(upstream_pin).c_str(), netlist.pin_name(driver_pin).c_str());