本节讲解7系器件的ODDR原语。
ODDR(Output Double Data Rate)原语用于将单沿(SDR)输入信号转换为双沿(DDR)信号,如一些DDR、LVDS等接口就需要使用双沿信号去提高数据传输速率。
ODDR框图:
原语框图如上图所示,其中S/R为同一根线,Set和Reset不能同时使用。
ODDR例化:
ODDR #(
.DDR_CLK_EDGE(“OPPOSITE_EDGE”), // “OPPOSITE_EDGE” or “SAME_EDGE”
.INIT(1’b0), // Initial value of Q: 1’b0 or 1’b1
.SRTYPE(“SYNC”) // Set/Reset type: “SYNC” or “ASYNC”
) ODDR_inst (
.Q(Q), // 1-bit DDR output
.C©, // 1-bit clock input
.CE(CE), // 1-bit clock enable input
.D1(D1), // 1-bit data input (positive edge)
.D2(D2), // 1-bit data input (negative edge)
.R®, // 1-bit reset
.S(S) // 1-bit set
);
例化共3个参数和7个端口;
ODDR例化端口:
端口如上图所示,
Q1:输出的双沿信号;
C:时钟输入端口;
CE:时钟使能,使能情况下ODDR才能正常工作,置高有效;
D1、D2:ODDR寄存器输入,单沿信号;
S/R:异步/同步的置位/复位管脚,为高有效且同一时刻只能有一个端口生效,使用注意参 照前述的IDDR的S\R管脚,避免同时激活两个端口即可;
ODDR例化参数:
参数DDR_CLK_EDGE:ODDR的操作模式,有OPPOSITE_EDGE、SAME_EDGE两种值可选,默认OPPOSITE_EDGE模式;
参数INIT:Q端口初始化值,0、1可选,默认0;
参数SRTYPE:置位和复位的同步或是异步的选择,可选值SYNC、ASYNC;
ODDR两种操作模式:
7系架构ODDR原语只需要输入一个时钟C,组件原语内部将会将C反相生成一个时钟~C去控制下降沿数据的控制;
OPPOSITE_EDGE模式:
D1在时钟上升沿采样并立即输出,
D2在时钟下降沿采样并立即输出,
每个时钟周期内,Q输出两个数据,上升沿输出D1,下降沿输出D2;
SAME_EDGE模式:
D1和D2均在时钟上升沿采样,
D1在时钟上升沿采样后立即输出,
D2则在上升沿采样后被锁定,直到下降沿到来时将数据输出,
每个时钟周期内,Q输出两个数据,上升沿输出D1,下降沿输出D2,两个模式下输出数据格式相同;
ODDR仿真:
被测试模块:
module top_7series_oddr(
input wire clk,
input wire rst,
input wire set,
input wire clk_en,
input wire din1,
input wire din2,
output wire dout
);
ODDR #(
.DDR_CLK_EDGE(“OPPOSITE_EDGE”), // “OPPOSITE_EDGE” or “SAME_EDGE”
.INIT(1’b0), // Initial value of Q: 1’b0 or 1’b1
.SRTYPE(“SYNC”) // Set/Reset type: “SYNC” or “ASYNC”
) ODDR_inst (
.Q(dout), // 1-bit DDR output
.C(clk), // 1-bit clock input
.CE(clk_en), // 1-bit clock enable input
.D1(din1), // 1-bit data input (positive edge)
.D2(din2), // 1-bit data input (negative edge)
.R(rst), // 1-bit reset
.S(set) // 1-bit set
);
endmodule
testbench:
产生40ns的时钟,;
`timescale 1ns / 1ps
module tb;
reg clk;
reg rst;
reg set;
reg data1;
reg data2;
reg clk_en;
wire dout;
initial begin
clk = 0;
rst = 1;
#200
rst = 0;
end
always #20 clk = ~clk;
initial begin
data1 = 0;
data2 = 0;
#10
while(1)begin
#20
data1 = $random();
data2 = $random();
end
end
initial begin
clk_en = 0;
#200
clk_en = 1;
#2000
clk_en = 0;
end
initial begin
set = 0;
#1000
set = 1;
#200
set = 0;
end
top_7series_oddr inst_top_7series_oddr(
.clk (clk),
.rst (rst),
.set (set),
.clk_en (clk_en),
.din1 (data1),
.din2 (data2),
.dout (dout)
);
endmodule
仿真结果:
时钟使能、置位、复位的效果:
从上图可以看出,clk_en始终使能拉高,原语才正常工作,否则输出保持不变;
set置1,这时dout强制输出置1;
rst置1复位,dout输出保持参数设置的初始化值0;
OPPOSITE_EDGE模式:
SAME_EDGE模式:
上面两图分别是OPPOSITE_EDGE模式和SAME_EDGE模式下的波形;
由于从上面截取的官方文档的时序波形图中可以看出,正确的数据输入应该是din1和din2每个clk时钟周期保持不变,但是如此按时序图提供的输入方式的话这两种模式下,输出格式都是一致的,那么我们就无法看到这两种模式有何区别了,所以这里将输入改为半个周期变换一次,所以我们就可以看出,上图两个模式下,输入信号其实是完全一致的,但是输出的dout信号却大不相同;
OPPOSITE_EDGE模式下,上升沿采集din1数据输出到dout,下降沿采集din2输出到dout;
SAME_EDGE模式下,上升沿同时采集din1和din2数据,但是din1先在这个采集的上升沿输出到dout,din2则寄存等到紧接着的下降沿输出到dout;
所以由于输入信号半周期变化一次,所以两个模式下din1采集的都是一样的数据,但是din2一个在上升沿采集,一个在下降沿采集,两个沿间隔半个周期,输入数据发生了变化,所以输出数据也就发生了变化;
但是请注意,本次这种提供输入数据的方式仅限于此次仿真用于验证其组件原语的功能模式,在正常使用时输入数据要保持一个周期才变换一次,不然会造成数据丢失、亚稳态等时序违例问题。
本文章由威三学社出品
对课程感兴趣可以私信联系