问题
遇到一个特别有意思的问题,链接: hdlbits.,其中模块描述如下:
module top_module (
input clk,
input d,
output q
);
要求根据d信号的输入,输出q,但是d信号是在clk信号的双边沿变化,而q需要偏移d的半个周期,并跟随d的值变化。
解决1?
难道always语句同时在上升沿和下降沿捕捉信号d?
verilog
module top_module (
input clk,
input d,
output q
);
reg q_reg;
always@(posedge clk,negedge clk)begin
q_reg<=d;
end
assign q= q_reg;
endmodule
好家伙直接综合不了。
ERROR: [Synth 8-91] ambiguous clock in event control。//事件控制表达式不明确
意味着always语句是无法同时将上升沿和下降沿设置成敏感延,那要是设置电平敏感呢?,在d高电平时,就输出q高电平,d低电平就输出q低电平。
解决2?
verilog
module top_module (
input clk,
input d,
output q
);
reg q_reg;
always@(clk)begin
q_reg = d;
end
assign q= q_reg;
endmodule
直接综合成q直接连接d,只是vivado插入了IBUF,OBUF,虽然q确实是随着d变化的,但是它们之间的相位根本无法控制。也就无法完成寄存器用来稳定数据的功能。
rtl
解决3?
verilog
换个思路,虽然always语句无法同时设置两种敏感事件,那要是用一个always对上升沿敏感,一个always对下降沿敏感,并利用clk的电平变化,clk高电平输出always对上升沿敏感捕获的值,clk低电平输出always对下降沿敏感捕获的值,这样交替就可以输出双边沿变化d的信号。
module top_module (
input clk,
input d,
output q
);
reg q1,q2,q_reg;
assign q = q_reg;
always@(posedge clk)begin
q1<=d;
end
always@(negedge clk)begin
q2<=d;
end
always@(clk)begin
if(clk)
q_reg = q1;
else
q_reg = q2;
end
endmodule
rtl
sim
module tb(
);
reg clk;
reg switch;
reg d1,d2;
initial begin
clk = 0;
switch = 0;
d1 = 0;
d2 = 0;
#1 switch = 1;
end
always #10 clk = ~clk;
wire q;
wire d,Q;
always @(posedge clk)
d1<= $random;
always @(negedge clk)
d2<= $random;
ODDR #(
.DDR_CLK_EDGE("SAME_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"
) orrt_test (
.Q(Q), // 1-bit DDR output
.C(clk), // 1-bit clock input
.CE(1'b1), // 1-bit clock enable input
.D1(d1), // 1-bit data input (positive edge)
.D2(d2), // 1-bit data input (negative edge