`timescale 1ns/1ps
module freq ();
reg clk_250 = 1'b0 ;
reg rst = 1'b1 ;
reg [6 : 0] cnt = 7'd0 ;
reg valid = 1'b0 ;
reg [2 : 0] valid_cnt = 3'd0 ;
parameter PERIOD_250 = 4 ;
//产生250MHZ时钟
initial
begin
clk_250 = 0;
forever #(PERIOD_250/2) clk_250 = ~clk_250;
end
initial
begin
#8 rst = 1'b0 ;
end
always @ ( posedge clk_250 )
begin
if( rst == 1)
cnt <= 8'b0000_0000 ;
else
begin
if( cnt == 8'd100 )
cnt <= 8'd1 ;
else
cnt <= cnt + 8'b1;
end
end
always @ ( posedge clk_250 )
begin
if( rst == 1'b1 )
valid_cnt <= 3'd0 ;
else
begin
if( valid_cnt == 3'd6)
valid_cnt <= 3'd1;
else
valid_cnt <= valid_cnt + 3'd1;
end
end
always @ ( posedge clk_250 )
begin
if( rst == 1)
valid <= 1'b0 ;
else
begin
if( valid_cnt == 1)
valid <= 1'd1;
else
valid <= 1'd0;
end
end
endmodule
上面代码想实现的是1到100的数据进行循环。并且有一个valid信号标志有效位,每6个数据有一个valid信号。下面是我用modelsim仿真得到的仿真图。
自己认为的仿真图应该是下面这样。
非阻塞赋值的结果要在下一个clock的上升沿才能得出。也就是需要延迟一个clock。仿真图里面感觉就有点自相矛盾。在生成cnt信号和valid-cnt 信号时直接在当前的clock就产生数据。然而产生valid信号时却是在下一个时钟产生的。
自己接触verilog时间不常工作需要,所以必须要把这个点弄会。总结上面的问题,其实就一个,非阻塞赋值会使得到的数据延时一个clock吗?如果是如何解释cnt和valid-cnt信号的生成。如果不延时一个clock那么valid信号为什么在下一clock才得出结果。希望能够得到专业的回答!!!毕竟我写了这么多又做了这么多的工作。
这个我觉得应该从时间片的概念上解答
verilog的timeslot划分5个域:
Active region : 执行process语句,阻塞赋值,连续赋值,及非阻塞赋值的右侧求值事件,阻塞赋值和连续赋值会触发在该时刻的新事件。$display是在该region执行。
Inactive region : 执行 #0的阻塞赋值;
NBA region : 更新非阻塞赋值的LHS(左侧值);
Monitor region : 执行$monitor 和 $strobe等,不会触发任何其他事件的read-only region
process: 进程是Verilog中的独立执行单元,包括:原语(Primitives), 模块(Moules), initial过程块, always过程块, 连续赋值语句(assign), 异步任务(task)。在仿真时,所有的进程都是仿真器按Verilog的语义来顺序执行的,效果是各个进程并行执行的效果,在未执行完当前所有的进程时,仿真时间不会向前推进。
你这个例子就是先在active region执行了porcess 这个时候非阻塞运算的cnt值( 处在右侧求值阶段) ,cnt实际值=6,执行判断语句(cnt == 1)当然就不成立,active region执行然后才会跳转到NBA region ,更新非阻塞赋值的左侧值 即cnt在此刻才变成1
https://wenku.baidu.com/view/74f85228ed630b1c59eeb51c.html
非阻塞赋值,中每个<=都会占用一个时钟
cnt 、valid cnt和valid都是下一个时钟得出结果。
比如,代码中rst==1的时候,cnt保持为0,rst刚变化为0的第一个周期,语句是走的cnt <= cnt + 1,但是下一个周期,cnt才变成1。
valid也是同样的,在valid cnt为1的时候,走的是valid <=1这条语句,但是下一个周期valid才会赋值为1。
很簡單,
cnt和valid-cnt都是宣告為序向邏輯, 所以這兩個訊後都是要等clk敲完下一個cycle才會產生
簡單講, valid-cnt的部分改成組合邏輯的寫法, always(...or ...) begin xxx=ooo ... end, 就會是你要的答案
图中现象涉及到verilog仿真语义。
硬件来说
针对valid信号,因为在valid_cnt == 1时, 才会运行 valid <= 1'd1。
而valid_cnt =1 是在触发器hold之后,所以在第一个时钟上升沿时,条件valid_cnt == 1不成立,所以valid不会发生变化。
在第二个时钟上升沿到来时,valid_cnt == 1,这时才开始运行valid。此时valid_cnt刚刚由1变成2。
这个问题已经过去很久了,刚刚自己也碰到了这个问题,看了一些书和博客。不知道这样理解对不对。