SDC: use fastest clock as ABC9 delay target
Signed-off-by: Dan Ravensloft <dan.ravensloft@gmail.com>
diff --git a/sdc-plugin/clocks.cc b/sdc-plugin/clocks.cc
index 6dbb962..5b60700 100644
--- a/sdc-plugin/clocks.cc
+++ b/sdc-plugin/clocks.cc
@@ -140,3 +140,23 @@
}
return clock_wires;
}
+
+void Clocks::UpdateAbc9DelayTarget(RTLIL::Design *design)
+{
+ std::map<std::string, RTLIL::Wire *> clock_wires = Clocks::GetClocks(design);
+
+ for (auto &clock_wire : clock_wires) {
+ auto &wire = clock_wire.second;
+ float period = Clock::Period(wire);
+
+ // Set the ABC9 delay to the shortest clock period in the design.
+ //
+ // By convention, delays in Yosys are in picoseconds, but ABC9 has
+ // no information on interconnect delay, so target half the specified
+ // clock period to give timing slack; otherwise ABC9 may produce a
+ // mapping that cannot meet the specified clock.
+ int abc9_delay = design->scratchpad_get_int("abc9.D", INT32_MAX);
+ int period_ps = period * 1000.0 / 2.0;
+ design->scratchpad_set_int("abc9.D", std::min(abc9_delay, period_ps));
+ }
+}
diff --git a/sdc-plugin/clocks.h b/sdc-plugin/clocks.h
index b11d1c0..f565299 100644
--- a/sdc-plugin/clocks.h
+++ b/sdc-plugin/clocks.h
@@ -64,6 +64,7 @@
{
public:
static const std::map<std::string, RTLIL::Wire *> GetClocks(RTLIL::Design *design);
+ static void UpdateAbc9DelayTarget(RTLIL::Design *design);
};
#endif // _CLOCKS_H_
diff --git a/sdc-plugin/sdc.cc b/sdc-plugin/sdc.cc
index 9f92b48..eafb894 100644
--- a/sdc-plugin/sdc.cc
+++ b/sdc-plugin/sdc.cc
@@ -323,6 +323,8 @@
for (auto &pass : passes) {
pass->Run();
}
+
+ Clocks::UpdateAbc9DelayTarget(design);
}
};
diff --git a/sdc-plugin/tests/Makefile b/sdc-plugin/tests/Makefile
index 503c542..1361f8e 100644
--- a/sdc-plugin/tests/Makefile
+++ b/sdc-plugin/tests/Makefile
@@ -1,3 +1,4 @@
+# abc9 - test that abc9.D is correctly set after importing a clock.
# counter, counter2, pll - test buffer and clock divider propagation
# set_false_path - test the set_false_path command
# set_max_delay - test the set_max_delay command
@@ -7,7 +8,8 @@
# waveform_check - test if the WAVEFORM attribute value is correct on wire
# period_format_check - test if PERIOD attribute value is correct on wire
-TESTS = counter \
+TESTS = abc9 \
+ counter \
counter2 \
pll \
pll_div \
@@ -28,6 +30,7 @@
include $(shell pwd)/../../Makefile_test.common
+abc9_verify = true
counter_verify = $(call diff_test,counter,sdc) && $(call diff_test,counter,txt)
counter2_verify = $(call diff_test,counter2,sdc) && $(call diff_test,counter2,txt)
pll_verify = $(call diff_test,pll,sdc)
diff --git a/sdc-plugin/tests/abc9/abc9.sdc b/sdc-plugin/tests/abc9/abc9.sdc
new file mode 100644
index 0000000..0a192c3
--- /dev/null
+++ b/sdc-plugin/tests/abc9/abc9.sdc
@@ -0,0 +1,3 @@
+create_clock -period 10 clk1
+create_clock -period 20 clk2
+propagate_clocks
diff --git a/sdc-plugin/tests/abc9/abc9.tcl b/sdc-plugin/tests/abc9/abc9.tcl
new file mode 100644
index 0000000..22766a1
--- /dev/null
+++ b/sdc-plugin/tests/abc9/abc9.tcl
@@ -0,0 +1,12 @@
+yosys -import
+if { [info procs read_sdc] == {} } { plugin -i sdc }
+yosys -import ;# ingest plugin commands
+
+# ensure abc9.D is unset
+scratchpad -assert-unset abc9.D
+
+read_verilog abc9.v
+read_sdc abc9.sdc
+
+# check that abc9.D was set to half the fastest clock period in the design
+scratchpad -assert abc9.D 5000
diff --git a/sdc-plugin/tests/abc9/abc9.v b/sdc-plugin/tests/abc9/abc9.v
new file mode 100644
index 0000000..5b73e55
--- /dev/null
+++ b/sdc-plugin/tests/abc9/abc9.v
@@ -0,0 +1,15 @@
+module top(input clk1, clk2, output led1, led2);
+
+reg [15:0] counter1 = 0;
+reg [15:0] counter2 = 0;
+
+assign led1 = counter1[15];
+assign led2 = counter2[15];
+
+always @(posedge clk1)
+ counter1 <= counter1 + 1;
+
+always @(posedge clk2)
+ counter2 <= counter2 + 1;
+
+endmodule