如何保证RTL设计与综合后网表的一致性

http://hi.baidu.com/hieda/blog/item/1754402924bed7f999250afa.html

文章简介:在超大规模数字集成电路的设计中,我们使用逻辑综合工具来完成从RTL设计到门级网表的转化。我们希望它综合出的门级网表与我们的RTL 设计在逻辑和时序上完全一致。但是某些书写风格和设计思路却会造成两者不一致的情况,降低我们的工作效率。本文列举了三种RTL设计与综合后网表不一致的 情况,并给出了解决方法.我们以Design Compiler为例,来说明设计RTL时应该注意的问题。在仿真和调试时,我们使用了NC-Verilog和Debussy。

1.不完整的敏感量列表
在下面的例子中,有一个always语句,它描述了一个或门,其中它的敏感量列表包含IN1和IN2。
/////////////////////////////////////////////////////////////////////////////
module OR_GATE_A (OUT_A, IN1, IN2);
output OUT_A;
input IN1, IN2;
reg OUT_A;
always @(IN1 or IN2)
OUT_A = IN1 | IN2;
endmodule
/////////////////////////////////////////////////////////////////////////////
再看下面的例子,敏感量列表只包含IN1。
/////////////////////////////////////////////////////////////////////////////
module OR_GATE_B (OUT_B, IN1, IN2);
output OUT_B;
input IN1, IN2;
reg OUT_B;
always @(IN1)
OUT_B = IN1 | IN2;
endmodule
/////////////////////////////////////////////////////////////////////////////
这两个例子有什么不同呢?我们看下面的波形:

对比两个module的输出,可以看出:它们的输入相同,但是输出在22时刻却不同,这是因为OR_GATE_B的敏感量列表只包含IN1,导致在22时刻虽然IN2发生了变化,却不能触发OUT_B重新求值。
我们看逻辑综合后的情况。
这两个module的逻辑综合的结果完全相同,均包含完整的敏感量列表。因此,对于OR_GATE_B,它会有RTL设计与综合后的网表不一致的问题。
避免这种问题的方法有二:

  1. 使用数据流的描述方法描述组合逻辑;
  2. 若用always语句描述组合逻辑,必须检查敏感量列表是否完整;

显然,采用第一种方法更简单一些。

2.时序延迟(timing delay)
我们在进行建模时,常常含有时间延迟。而时间延迟是不可综合的对象,因此,如果建模时不注意时间延迟的"必要的准确性",便会造成时序上的不一致,进而造成逻辑结果上的不一致。我们看下面的例子。
例子:一个二级延迟线
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
module mis_timing (
A ,
DATA_RDY,
VE_CLK,
VE_RSTJ,
OUT,
OUT_RDY
);
parameter A_WIDTH = 3;
input [A_WIDTH-1:0]A;
input DATA_RDY;
input VE_RSTJ;
input VE_CLK;
output OUT;
output OUT_RDY;
reg OUT_RDY;
reg DATA_RDY_DLY1;
reg DATA_RDY_DLY2;
reg [A_WIDTH-1:0]OUT ;
parameter UDLY = 1;
//---time for one clock cycle
parameter CLOCK_CYCLE=6.5 ;
always@(posedge VE_CLK or negedge VE_RSTJ) //the data addr
if (!VE_RSTJ)
OUT <= #UDLY 'd0 ;
else OUT <= #(UDLY+CLOCK_CYCLE) A;
//---- output ready ------------------
always@(posedge VE_CLK or negedge VE_RSTJ)
if (!VE_RSTJ)
OUT_RDY <= #UDLY 'd0 ;
else OUT_RDY <= #(UDLY+CLOCK_CYCLE) DATA_RDY;
endmodule
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
在这个行为级描述中,我们使用了一个超过一个时钟周期的延迟。
我们使用下面的仿真文件进行仿真:
/////////////////////////////////////////////////////////////////////////////////////////////////////
module ts;
parameter A_WIDTH = 3;
reg [A_WIDTH-1:0]A;
reg DATA_RDY;
reg VE_CLK;
reg VE_RSTJ;
mis_timing mis_timing
(.A (A ),
.DATA_RDY(DATA_RDY ),
.VE_CLK (VE_CLK ),
.VE_RSTJ (VE_RSTJ ),
.OUT ( ),
.OUT_RDY ( )
);
//----------- input data----------------------
initial begin
#2 A=0;
#10 A=0; DATA_RDY=0;
#6 A=3'h5; DATA_RDY=1;
#6.5 A=3'h5; DATA_RDY=0;
end
//-------------clock and RST signal -------------
initial begin
#1 VE_CLK=1'b0;
forever #3.2 VE_CLK= ~VE_CLK;
end
initial begin
#1 VE_RSTJ =1'b1;
#10 VE_RSTJ =1'b0;
#7 VE_RSTJ =1'b1;
end
//---------- waveform dump---------------
initial begin
$fsdbDumpfile("delay_line.fsdb");
$fsdbDumpvars(0,ts );
end
//-------------finish-----------------------------
initial begin
#100 $finish;
end
endmodule
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
我们看它的波形效果:

使用逻辑综合工具后,得到门级网表文件如下:
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
module mis_timing ( A, DATA_RDY, VE_CLK, VE_RSTJ, OUT, OUT_RDY, TEST_SI, TEST_SO, test_se );
input [2:0] A;
output [2:0] OUT;
input DATA_RDY, VE_CLK, VE_RSTJ, TEST_SI, test_se;
output OUT_RDY, TEST_SO;
wire n7, n8, n9;
BUFX8 I3 ( .A(n7), .Y(OUT[1]) );
BUFX8 I4 ( .A(n8), .Y(OUT[0]) );
BUFX8 I5 ( .A(TEST_SO), .Y(OUT[2]) );
BUFX8 I6 ( .A(n9), .Y(OUT_RDY) );
SDFFRHQX2 OUT_RDY_reg ( .SI(TEST_SI), .SE(test_se), .D(DATA_RDY), .CK(
VE_CLK), .RN(VE_RSTJ), .Q(n9) );
SDFFRHQX2 \OUT_reg[0] ( .SI(n9), .SE(test_se), .D(A[0]), .CK(VE_CLK),
.RN(VE_RSTJ), .Q(n8) );
SDFFRHQX2 \OUT_reg[1] ( .SI(n8), .SE(test_se), .D(A[1]), .CK(VE_CLK),
.RN(VE_RSTJ), .Q(n7) );
SDFFRHQX2 \OUT_reg[2] ( .SI(n7), .SE(test_se), .D(A[2]), .CK(VE_CLK),
.RN(VE_RSTJ), .Q(TEST_SO) );
endmodule
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
研究这个网表文件,我们发现从输入到输出只有一级延迟,显然这与RTL设计不符,因此产生了不匹配。
注:我们在逻辑综合时加上了扫描链,所以有TEST_SI, TEST_SO, test_se这三个信号。
我们看综合后的仿真波形:

比较两个波形,可以直观的看出这种不匹配现象。为了避免这种情况的发生,我们必须改正原来的RTL设计。
//改正RTL
//////////////////////////////////////////////////////////////////////////////////////////////////////////
module mis_timing (
A ,
DATA_RDY,
VE_CLK,
VE_RSTJ,
OUT,
OUT_RDY
);
parameter A_WIDTH = 3;
input [A_WIDTH-1:0]A;
input DATA_RDY;
input VE_RSTJ;
input VE_CLK;
output OUT;
output OUT_RDY;
reg OUT_RDY;
reg DATA_RDY_DLY1;
reg [A_WIDTH-1:0]OUT ;
parameter UDLY = 1;
//---time for one clock cycle
parameter CLOCK_CYCLE=6.5 ;
always@(posedge VE_CLK or negedge VE_RSTJ) //the data addr
if (!VE_RSTJ)
OUT <= #UDLY 'd0 ;
else if (DATA_RDY )
OUT <= #(UDLY) A;
//---- output ready ------------------
always@(posedge VE_CLK or negedge VE_RSTJ)
if (!VE_RSTJ)
DATA_RDY_DLY1 <= #UDLY 'd0 ;
else DATA_RDY_DLY1 <= #UDLY DATA_RDY;
always@(posedge VE_CLK or negedge VE_RSTJ)

if (!VE_RSTJ)
OUT_RDY <= #UDLY 'd0 ;
else OUT_RDY <= #UDLY DATA_RDY_DLY1 ;
endmodule

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
我们总结避免这种不匹配的方法:
除非一个逻辑运算在一个时钟周期内无法完成(或者你要仿真一条延迟太长的连线),在设计可综合的RTL代码时,一般不要用超过一个周期的时间延迟。

3.多周期路径(multi-cycle path)引起的问题
在含有时钟的电路中,某些较复杂的组合逻辑运算无法在一个周期内完成,而是需要多个周期来完成,我们称这条逻辑路径为多周期路径(Multi-cycle Path)。
我们看下面的例子:
我们来实现一个17/6的无符号整数除法,被除数为A,除数为B;DATA_RDY为一个脉冲信号,当它为高时对应的A,B为有效值。
我们设计RTL code如下:
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
module multi_cycle (
A ,
B ,
DATA_RDY,
VE_CLK,
VE_RSTJ,
OUT,
OUT_RDY
);
parameter A_WIDTH = 17;
parameter B_WIDTH = 6;
input [A_WIDTH-1:0]A;
input [B_WIDTH-1:0]B;
input DATA_RDY;
input VE_RSTJ;
input VE_CLK;
output OUT;
output OUT_RDY;
reg OUT_RDY;
reg [A_WIDTH-1:0]OUT ;
parameter UDLY = 1;
wire [(A_WIDTH-1):0] DATA_TMP= A / B ;
always@(posedge VE_CLK or negedge VE_RSTJ) if (!VE_RSTJ)
OUT = #UDLY 'd0 ;
else if (DATA_RDY)
OUT = #UDLY DATA_TMP;
//---- output ready ------------------
always@(posedge VE_CLK or negedge VE_RSTJ)
if (!VE_RSTJ)
OUT_RDY <= #UDLY 'd0 ;
else OUT_RDY <= #UDLY DATA_RDY ;
endmodule

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
我们用以下的仿真文件来完成仿真:
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
module ts;
parameter A_WIDTH = 17;
parameter B_WIDTH = 6;
reg [A_WIDTH-1:0]A;
reg [B_WIDTH-1:0]B;
reg DATA_RDY;
reg RDY_DLY;
reg VE_CLK;
reg VE_RSTJ;
multi_cycle multi_cycle
(
.A (A ),
.B (B ),
.DATA_RDY(DATA_RDY ),
.VE_CLK (VE_CLK ),
.VE_RSTJ (VE_RSTJ ),
.OUT ( ),
.OUT_RDY ( )
);
//----------- input data----------------------
initial
begin
#2 A=0; B=0;
#10 A=0; B=0; DATA_RDY=0;
#6 A=17'h15505; B=7'h55; DATA_RDY=1;
#6.5 A=17'h15505; B=7'h55; DATA_RDY=0;
end
//-------------clock and RST signal -------------
initial begin
#1 VE_CLK=1'b0;
forever #3.2 VE_CLK= ~VE_CLK;
end
initial begin
#1 VE_RSTJ =1'b1;
#10 VE_RSTJ =1'b0;
#7 VE_RSTJ =1'b1;
end
//------- waveform dump: I use debussy as debug tool----
initial begin
$fsdbDumpfile("multi_cycle.fsdb");
$fsdbDumpvars(0,ts );
end
//-------------finish-----------------------------
initial begin
#100 $finish;
end
endmodule
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
我们看它的波形:

//逻辑综合
我们来完成它的逻辑综合:使用的单元库为UMC的UMC018AG_AASW。
逻辑综合时,我们设定时钟周期为6.5ns;
逻辑综合完成后,得到时序报告文件,下面是它的一部分:
****************************************
Report : timing
-path full
-delay max
-max_paths 3
Design : multi_cycle
Version: 2002.05
Date : Wed Dec 29 16:15:22 2004
****************************************
Operating Conditions: slow Library: UMC018AG_AASW
Wire Load Model Mode: top
Startpoint: B[2] (input port clocked by VE_CLK)
Endpoint: OUT_reg[0] (rising edge-triggered flip-flop clocked by VE_CLK)
Path Group: VE_CLK
Path Type: max
Des/Clust/Port Wire Load Model Library
------------------------------------------------
multi_cycle UMC18_Conservative UMC018AG_AASW
Point Incr Path
--------------------------------------------------------------------------
clock VE_CLK (rise edge) 0.00 0.00
clock network delay (ideal) 0.00 0.00
input external delay 1.00 1.00 r
B[2] (in) 0.05 1.05 r
div_30/b[2] (multi_cycle_DW_div_uns_17_6_1_test_1) 0.00 1.05 r
div_30/U228/Y (BUFX20) 0.17 1.22 r
......
OUT_reg[0]/D (SDFFRXL) 0.00 13.24 f
data arrival time 13.24
clock VE_CLK (rise edge) 7.00 7.00
clock network delay (ideal) 0.00 7.00
clock uncertainty -0.50 6.50
OUT_reg[0]/CK (SDFFRXL) 0.00 6.50 r
library setup time -0.41 6.09
data required time 6.09
--------------------------------------------------------------------------
data required time 6.09
data arrival time -13.24
--------------------------------------------------------------------------
slack (VIOLATED) -7.15
可以看出,这个除法在13ns内才能完成,在这里时钟周期为6.4ns,因此这个除法含有多周期路径。这个路径需要的周期数为3个。
我们来分析这条多周期路径造成的后果:
也就是下属语句:
else if (DATA_RDY)
OUT = #UDLY DATA_TMP;
因为DATA_TMP的计算需要3个时钟周期,所以我们如果在DATA_RDY有效时对DATA_TMP采样,只能得到它的中间值,这自然是一个错误的值。为避免不匹配我们需要延迟两个周期后对DATA_TMP采样。
//改写RTL code
因此我们的文件改写为:
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
module multi_cycle (
A ,
B ,
DATA_RDY,
VE_CLK,
VE_RSTJ,
OUT,
OUT_RDY
);
parameter A_WIDTH = 17;
parameter B_WIDTH = 6;
input [A_WIDTH-1:0]A;
input [B_WIDTH-1:0]B;
input DATA_RDY;
input VE_RSTJ;
input VE_CLK;
output OUT;
output OUT_RDY;
reg OUT_RDY;
reg DATA_RDY_DLY1;
reg DATA_RDY_DLY2;
reg [A_WIDTH-1:0]OUT ;
parameter UDLY = 1;
wire [(A_WIDTH-1):0] SUM_TMP= A / B ;
always@(posedge VE_CLK or negedge VE_RSTJ) //the data addr
if (!VE_RSTJ)
OUT <= #UDLY 'd0 ;
else if (DATA_RDY_DLY2)
OUT <= #UDLY SUM_TMP;
//---- output ready ------------------
always@(posedge VE_CLK or negedge VE_RSTJ)
if (!VE_RSTJ)
DATA_RDY_DLY1 <= #UDLY 'd0 ;
else DATA_RDY_DLY1 <= #UDLY DATA_RDY;
always@(posedge VE_CLK or negedge VE_RSTJ)
if (!VE_RSTJ)
DATA_RDY_DLY2 <= #UDLY 'd0 ;
else DATA_RDY_DLY2 <= #UDLY DATA_RDY_DLY1;
always@(posedge VE_CLK or negedge VE_RSTJ)
if (!VE_RSTJ)
OUT_RDY <= #UDLY 'd0 ;
else OUT_RDY <= #UDLY DATA_RDY_DLY2 ;
endmodule
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//重新综合---
得到逻辑网表文件(.net)和延迟文件(.sdf)
///综合后的仿真波形:

//总结:避免此种不匹配的方法:
当我们的RTL设计中含有运算复杂,延迟较大的路径时,我们应该根据我们的时钟和使用的单元库,评估它会不会是多周期路径。如果是多周期路径,要看看它是否会造成逻辑和时序错误,然后对RTL代码做必要的修改。

4.总结
在进行RTL设计时,为了保证RTL设计与综合后网表的一致,应注意:

  1. 结合所选用的逻辑综合工具的特点,使用合适的书写方式;
  2. 了解所使用的标准库单元的速度;
  3. 明确硬件电路时钟的频率,并估计一些复杂运算在一个周期内能否完成;

5.参考文献
1)Don Mills, Clifford E. Cummings, RTL Coding Styles That Yield Simulation and Synthesis Mismatches,SNUG1999。
2)Samir Palnitkar, VERILOG HDL, A Guide to DIGITAL Design and Synthesis, Sunsoft Press
作者:王振国
科广新(北京)信息技术公司


posted @ 2011-05-22 09:35  Hello Verilog  阅读(2107)  评论(0编辑  收藏  举报