设计意图应该与设计状态一致,但在实现的RTL代码中,二者却不一定一致。时钟约束的描述这时应该反映设计状态,而不是文档中设计意图,这样,时序检查才有机会发现问题,然后反馈给设计人员。要做到这一点,需要对时钟生成的RTL进行分析,真实地描述出来。这就是本文的出发点。
module div(
clk, rstn, clkout,
cnter,din, dout
);
input clk, rstn, din;
input [2:0] cnter;
output reg clkout;
output reg dout;
reg normal_div2, normal_div4, normal_div8;
reg cnt_div, upcnt_div;
reg up_cnt_div;
reg inverted_div2, inverted_div4, inverted_div8;
reg [8:0] dnom_tmp; //use normal_divx as clock
reg [8:0] dinv_tmp; //use normal_divx as clock
reg [8:0] dcnt_tmp; //use clk_cnt as clock
reg [8:0] dup_tmp; //use clk_cnt as clock
reg [2:0] counter, upcounter;
//normal div
always @(posedge clk or negedge rstn)
if(!rstn)
normal_div2 <= 1'b0;
else
normal_div2 <= ~normal_div2;
always @(posedge normal_div2 or negedge rstn)
if(!rstn)
normal_div4 <= 1'b0;
else
normal_div4 <= ~normal_div4;
always @(posedge normal_div4 or negedge rstn)
if(!rstn)
normal_div8 <= 1'b0;
else
normal_div8 <= ~normal_div8;
// inverted div
always @(posedge clk or negedge rstn)
if(!rstn)
inverted_div2 <= 1'b1;
else
inverted_div2 <= ~inverted_div2;
always @(posedge inverted_div2 or negedge rstn)
if(!rstn)
inverted_div4 <= 1'b1;
else
inverted_div4 <= ~inverted_div4;
always @(posedge inverted_div4 or negedge rstn)
if(!rstn)
inverted_div8 <= 1'b1;
else
inverted_div8 <= ~inverted_div8;
//counter div
always @(posedge clk or negedge rstn)
if(!rstn)
cnt_div <= 1'b0;
else if (counter== 0)
cnt_div <= ~cnt_div ; // cnter = 1,3,7
always @(posedge clk or negedge rstn)
if(!rstn)
counter <= 3'h7;
else if(counter==0)
counter <= cnter;
else
counter <= counter - 1;
//up counter div
always @(posedge clk or negedge rstn)
if(!rstn)
upcounter <= 3'h0;
else if(upcounter==cnter)
upcounter <= 3'h0;
else
upcounter <= upcounter + 1;
always @(posedge clk or negedge rstn)
if(!rstn)
upcnt_div <= 1'b0;
else if (upcounter== cnter)
upcnt_div <= ~upcnt_div ; // cnter = 1,3,7
// use clock here
always@(posedge clk or negedge rstn)
if(!rstn)
dnom_tmp[0] <= 1'b0;
else
dnom_tmp[0] <= din;
always@(posedge normal_div2 or negedge rstn)
if(!rstn)
dnom_tmp[2] <= 1'b0;
else
dnom_tmp[2] <= din;
always@(posedge normal_div4 or negedge rstn)
if(!rstn)
dnom_tmp[4] <= 1'b0;
else
dnom_tmp[4] <= din;
always@(posedge normal_div8 or negedge rstn)
if(!rstn)
dnom_tmp[8] <= 1'b0;
else
dnom_tmp[8] <= din;
//inverted clock
always@(posedge inverted_div2 or negedge rstn)
if(!rstn)
dinv_tmp[2] <= 1'b0;
else
dinv_tmp[2] <= din;
always@(posedge inverted_div4 or negedge rstn)
if(!rstn)
dinv_tmp[4] <= 1'b0;
else
dinv_tmp[4] <= din;
always@(posedge inverted_div8 or negedge rstn)
if(!rstn)
dinv_tmp[8] <= 1'b0;
else
dinv_tmp[8] <= din;
// counter
always@(posedge cnt_div or negedge rstn)
if(!rstn)
dcnt_tmp[1] <= 1'b0;
else
dcnt_tmp[1] <= din;
wire dout_tmp;
assign dout_tmp = ^{dnom_tmp[2],dnom_tmp[4],dnom_tmp[8]} | ^{dinv_tmp[2],dinv_tmp[4],dinv_tmp[8]} | dcnt_tmp[1] | dup_tmp[1] ;
// upcounter
always@(posedge upcnt_div or negedge rstn)
if(!rstn)
dup_tmp[1] <= 1'b0;
else
dup_tmp[1] <= din;
//phase shifted 90 degree
always@(negedge clk or negedge rstn)
if(!rstn)
clkout <= 1'b0;
else
clkout <= ~clkout;
always@(edge clkout or negedge rstn)
if(!rstn)
dout <= 1'b0;
else
dout <= dout_tmp;
endmodule
代码中的时钟比较多,但我们一段一段地分析。先看3个二分频。
仿真可以直观看出,
normal_div2是普通二分频
inverted_div2是 二分频的反相
clkout则是90度相移的二分频
create_clock -name clk [get_ports clk] -period 20
create_generated_clock -name nom_clk_div2 [get_pins normal_div2_reg/Q] -divide_by 2 -master clk -source [get_ports clk]
create_generated_clock -name inv_clk_div2 [get_pins inverted_div2_reg/Q] -invert -divide_by 2 -master clk -source [get_ports clk]
create_generated_clock -name sht_clk_div2 [get_pins clkout_reg/Q] -divide_by 2 -master clk -source [get_ports clk] -preinvert
set_app_var search_path "../ref ../ref/db ../rtl ./"
set_app_var target_library "sc_max.db"
set_app_var link_library "* sc_max.db dw_foundation.sldb"
set cache_write dc_sw_cache
set cache_read $cache_write
set alib_library_analysis_path dc_dw_cache
set synthetic_library {dw_foundation.sldb}
define_design_lib DEFAULT -path ./analyzed
set hdlin_enable_rtldrc_info true;
read_verilog ../rtl/div.v
current_design div
link
source div.sdc
compile
write -format ddc -hierarchy -output results/div.ddc
write -format verilog -hierarchy -output results/div.vg
report_clocks
Clock Period Waveform Attrs Sources
clk 20.00 {0 10} {clk}
inv_clk_div2 40.00 {20 40} G {inverted_div2_reg/Q}
nom_clk_div2 40.00 {0 20} G {normal_div2_reg/Q}
sht_clk_div2 40.00 {0 20} G {clkout_reg/Q}
前三个对,但是sht_clk_div2,那么 -preinvert不起作用吗?根据文档,creates a generated clock based on the inverted clock signal
only when the source clock on the master pin has a non-unate sense, or the generated clock will not be inverted just as this option has not been specified。所以不起作用符合工具说明。
create_generated_clock -name sht_clk_div2 [get_pins clkout_reg/Q] -edges {2 4 6} -master clk -source [get_ports clk]
clk 20.00 {0 10} {clk}
inv_clk_div2 40.00 {20 40} G {inverted_div2_reg/Q}
nom_clk_div2 40.00 {0 20} G {normal_div2_reg/Q}
sht_clk_div2 40.00 {10 30} G {clkout_reg/Q}
与波形一致。
Startpoint: dnom_tmp_reg[2]
(rising edge-triggered flip-flop clocked by nom_clk_div2)
Endpoint: dout_reg (rising edge-triggered flip-flop clocked by sht_clk_div2)
Path Group: sht_clk_div2
Path Type: max
Des/Clust/Port Wire Load Model Library
div 8000 cb13fs120_tsmc_max
Point Incr Path
clock nom_clk_div2 (rise edge) 0.00 0.00
clock network delay (ideal) 0.00 0.00
dnom_tmp_reg[2]/CP (dfcrq1) 0.00 0.00 r
dnom_tmp_reg[2]/Q (dfcrq1) 0.31 0.31 f
U7/Z (xr03d1) 0.32 0.62 f
U6/Z (or04d0) 0.22 0.84 f
dout_reg/D (dfcrq1) 0.00 0.84 f
data arrival time 0.84
clock sht_clk_div2 (rise edge) 10.00 10.00
clock network delay (ideal) 0.00 10.00
dout_reg/CP (dfcrq1) 0.00 10.00 r
library setup time -0.09 9.91
data required time 9.91
data required time 9.91
data arrival time -0.84
slack (MET) 9.06
这样,检查10ns,才能反映RTL的真实情况。
当然,实施了分析RTL来编写SDC,一共提供了三次机会。
(1)通过代码分析,波形比对,可以与设计文档核对,有问题,及时反馈给设计。
(2)通过review,也可以更快地让设计了解到问题点。
(3)最晚地,在STA阶段还有机会发现问题。