VCS中initial块连续赋值clk未触发always块的原因咨询
VCS中同一时间步连续赋值clk为何未触发D触发器更新?
Verilog设计与测试代码
module dff (clk, reset, d, q, qb); input clk; input reset; input d; output q; output qb; reg q; assign qb = ~q; always @(posedge clk or posedge reset) begin if (reset) begin // 异步复位(reset高有效) q <= 1'b0; end else begin // 时钟上升沿时将D赋值给Q q <= d; end end endmodule // 测试平台代码 module TB; reg clk; reg reset; reg d; wire q, qb; dff dff_inst(clk, reset, d, q, qb); initial begin clk = 0; reset = 0; d = 1; #1; reset = 1; #1; reset = 0; #1; //// 注意这里!!! clk = 0; clk = 1; clk = 0; #1; $display("q = %b", q); end endmodule
问题描述
我是VCS新手,为测试事件驱动机制,在initial块的同一时间步内将clk信号连续赋值为0、1、0。按照事件驱动逻辑,clk存在上升沿事件,应触发always块使q被赋值为1,但$display输出q为0,请问这是为什么?
原因分析
核心问题在于Verilog仿真的时间步与边沿检测机制:
- Verilog仿真以时间步为基本单位,信号的边沿(如
posedge clk)是基于相邻时间步之间的信号值变化来判定的,而非同一时间步内的瞬时跳变。 - 你在
#1后的同一时间步内,用阻塞赋值连续执行clk=0; clk=1; clk=0;,这组操作会在当前时间步的active区域内立即完成。此时该时间步开始时clk的值为0,执行完所有赋值后clk的最终值仍为0——仿真器只会识别时间步起始与结束的信号值差异,中间的瞬时1不会被判定为有效的上升沿事件。 - 由于未触发
always @(posedge clk or posedge reset)的敏感事件,D触发器的q <= d操作从未执行,q保持了异步复位后的0值,因此$display输出0。
验证与修正方法
- 验证上升沿检测逻辑:若将clk赋值改为最终停留在1,该时间步结束时clk值从0变为1,仿真器会识别出上升沿,触发always块更新q:
#1; clk = 0; clk = 1; // 不再赋值回0
此时$display会输出q = 1。
- 规范时钟生成方式:若要模拟完整的时钟脉冲,需将高低电平拆分到不同时间步,比如:
#1; clk = 1; #1; clk = 0;
这样能在相邻时间步产生有效的上升沿和下降沿,符合事件驱动的仿真逻辑。
内容的提问来源于stack exchange,提问作者jptang
相关产品推荐
相关产品推荐

