-
Notifications
You must be signed in to change notification settings - Fork 893
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4525 from georgerennie/peepopt_clock_gate
peepopt: Add formal opt to rewrite latches to ffs in clock gates
- Loading branch information
Showing
5 changed files
with
141 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
pattern formal_clockgateff | ||
|
||
// Detects the most common clock gating pattern using a latch and replaces it | ||
// with a functionally equivalent pattern based on a flip-flop. The latch | ||
// based pattern has a combinational path from the enable input to output after | ||
// clk2fflogic, but this is a stable loop and the flip-flop based pattern does | ||
// not exhibit this. | ||
// | ||
// This optimization is suitable for formal to prevent false comb loops, but | ||
// should not be used for synthesis where the latch is an intentional choice | ||
// | ||
// Latch style: | ||
// always @* if (!clk_i) latched_en = en; | ||
// assign gated_clk_o = latched_en & clk_i; | ||
// | ||
// Flip-flop style: | ||
// always @(posedge clk) flopped_en <= en; | ||
// assign gated_clk_o = flopped_en & clk_i; | ||
|
||
state <SigSpec> clk en latched_en gated_clk | ||
state <IdString> latched_en_port_name | ||
|
||
match latch | ||
select latch->type == $dlatch | ||
select param(latch, \WIDTH) == 1 | ||
select param(latch, \EN_POLARITY).as_bool() == false | ||
set clk port(latch, \EN) | ||
set en port(latch, \D) | ||
set latched_en port(latch, \Q) | ||
endmatch | ||
|
||
match and_gate | ||
select and_gate->type.in($and, $logic_and) | ||
select param(and_gate, \A_WIDTH) == 1 | ||
select param(and_gate, \B_WIDTH) == 1 | ||
select param(and_gate, \Y_WIDTH) == 1 | ||
choice <IdString> clk_port {\A, \B} | ||
define <IdString> latch_port {clk_port == \A ? \B : \A} | ||
index <SigSpec> port(and_gate, clk_port) === clk | ||
index <SigSpec> port(and_gate, latch_port) === latched_en | ||
set gated_clk port(and_gate, \Y) | ||
set latched_en_port_name latch_port | ||
endmatch | ||
|
||
code | ||
log("replacing clock gate pattern in %s with ff: latch=%s, and=%s\n", | ||
log_id(module), log_id(latch), log_id(and_gate)); | ||
|
||
// Add a flip-flop and rewire the AND gate to use the output of this flop | ||
// instead of the latch. We don't delete the latch in case its output is | ||
// used to drive other nodes. If it isn't, it will be trivially removed by | ||
// clean | ||
SigSpec flopped_en = module->addWire(NEW_ID); | ||
module->addDff(NEW_ID, clk, en, flopped_en, true, latch->get_src_attribute()); | ||
and_gate->setPort(latched_en_port_name, flopped_en); | ||
did_something = true; | ||
|
||
accept; | ||
endcode |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
read_verilog -sv <<EOT | ||
module peepopt_formal_clockgateff_0( | ||
input logic clk_i, | ||
input logic ena_i, | ||
input logic enb_i, | ||
output logic clk_o | ||
); | ||
|
||
logic en_latched; | ||
|
||
always_latch | ||
if (!clk_i) | ||
en_latched <= ena_i | enb_i; | ||
|
||
assign clk_o = en_latched & clk_i; | ||
|
||
endmodule | ||
EOT | ||
|
||
# Check original design has latch | ||
prep -auto-top | ||
select -assert-count 1 t:$dlatch | ||
select -assert-count 0 t:$dff | ||
|
||
# Manually execute equiv_opt like pattern so clk2fflogic is called with | ||
# -nopeepopt, otherwise this doesn't test anything | ||
design -save preopt | ||
check -assert | ||
peepopt -formalclk | ||
check -assert | ||
design -stash postopt | ||
|
||
# Create miter and clk2fflogic without peepopt | ||
design -copy-from preopt -as gold A:top | ||
design -copy-from postopt -as gate A:top | ||
clk2fflogic -nopeepopt | ||
equiv_make gold gate equiv | ||
equiv_induct equiv | ||
equiv_status -assert equiv | ||
|
||
# Check final design has dff instead of latch | ||
design -load postopt | ||
clean | ||
select -assert-count 0 t:$dlatch | ||
select -assert-count 1 t:$dff |