I am clock gating some latch and logic in my design. I don't have much experience in synthesis and place & route. What is the proper way to implement clock gating in RTL?
Example1:
always_comb begin
gated_clk = clk & latch_update_en;
end
always_latch begin
if(gated_clk) begin
latch_data <= new_data;
end
end
Example2: I stumbled into a RTL examples while doing some research about good practices in RTL clock gating. That example implemented the above code like this:
clock_gator cg_cell (.clk(clk), .en(latch_update_en), .scan_en(scan_en_in), .gated_clk(gated_clk));
always_latch begin
if(gated_clk) begin
latch_data <= new_data;
end
end
What is the purpose of using custom clock gating cell? Does the tool have hard time in synthesis if clk is directly "and"-ed in a always_comb block with another enable signal? I am having a feeling that using special clock gating cell is a standard approach to generated gated clock signal. I am trying to understand why this is the case.
The clock gating signal should only toggle when the latch is closed, otherwise there is a chance for glitches and metastability issues. For an active high latch, the gating signal should toggle on the falling edge of the clock. Rising edge for active low latches.
Normally you would use an edge sensitive flop to hold latch_update_en
to prevent noise on the gating signal.
always_ff @(negedge clk)
latch_update_en <= next_latch_update_en;
always_comb
gated_clk = (* clock_gating = "clk" *) clk & latch_update_en;
always_latch
if(gated_clk)
latch_data <= new_data;
Reminder: if you have a latch only deign: edge trigger flops are just master/slave latches
always_latch
if (clk)
sync_latch_update_en <= next_latch_update_en;
always_latch
if (!clk)
latch_update_en <= sync_latch_update_en;
Most synthesis do have have issues with directly AND-ing a clocking. It is not always intuitive how the gating should be used. A synthesizer often has many AND gates in the library to choose from, each one has different slew, skew, and loading that very on input combinations. Though functionally the same, A & B
will get different time results then B & A
.
Instantiating an explicit cell from the synthesizer's library narrows the possibilities to know and anticipated behavior. A predefined clock gating cell also has attributes used by the synthesizer. Attributes include timing information for balancing the clock tree (buffer placement in the design for managing loads and parasitic).
Some synthesizers support setting attributes tags in RTL (ex: // synthesis attributes
or (* attributes *)
) instead of needing to explicitly instantiate a cell. There isn't a standard for how this is do so refer to your user manual.
The custom cell is a per-defined cell in the synthesis library with know timing information, load balancing, and other attributes. With this information, the synthesizer knows where and how to add or calibrate the buffer delay in the clock tree. This making sure the non-gated flop doesn't see the clock edge before gated flop.
_____ _____
IN -------------|D Q|-----|D Q|--- OUT
| | | |
|\ |\ | | | |
+-| >| >---|> | +-|> |
| |/ |/ |_____| | |_____|
| ___ |
CLK -+-| \ |
| & )-------------+ BALANCED CLOCK : correct data sampled
GATE --|___/
Without the guidance, the gated flop's could get a delayed clock. The skew would cause the wrong data to get sampled.
_____ _____
IN -------------|D Q|-----|D Q|--- OUT
| | | |
| | | |
+----------|> | +-|> |
| |_____| | |_____|
| ___ |
CLK -+-| \ |\ |\ |
| & )---| >| >----+ UNBALANCED CLOCK : wrong data sampled
GATE --|___/ |/ |/