Verilator报「同一变量存在阻塞与非阻塞赋值」错误的问题咨询
解决Verilator提示「Blocked and non-blocking assignments to same variable」的问题
Verilator的这个错误提示虽然字面提到“阻塞和非阻塞赋值”,但你的问题本质是同一个变量被两个不同触发类型的always块同时驱动,再加上组合逻辑always块误用非阻塞赋值的编码问题,才触发了这个报错。
问题根源分析
组合逻辑
always块的错误用法:
你第一个always块是电平敏感的组合逻辑块(敏感列表为rst_b or addr1 or data_in1 or write_mask1),这类块的正确赋值方式是用阻塞赋值(=),而非阻塞赋值(<=)仅用于时序逻辑块(边沿触发)。在组合逻辑块里用非阻塞赋值本身就违反了SystemVerilog的编码规范,会导致仿真行为异常。跨类型
always块驱动同一变量:
你同时用组合逻辑块(电平触发)和时序逻辑块(posedge clk边沿触发)驱动data_out1,这在硬件设计中是不合法的——相当于给同一个信号接了两个独立的驱动源,会导致竞争和不确定的电路行为,Verilator会将这种情况判定为“阻塞式组合赋值”与“非阻塞式时序赋值”的混合,从而抛出错误提示。
解决方案
根据你的设计需求,选择以下两种修正方式:
方式1:将所有逻辑合并到时序逻辑块
如果data_out1是时序输出(应该由时钟同步),把原本分散在两个块里的逻辑合并到同一个边沿触发的always块中,同时规范复位逻辑:
output [31:0] data_out1; reg [31:0] data_out1; // 异步复位时序块(也可改为同步复位,根据需求调整) always @(posedge clk or negedge rst_b) begin if (!rst_b) begin data_out1 <= 32'h0; // 定义复位默认值 end else if (write_mask1 != 32'b0) begin // 合并两个原块中的赋值逻辑 data_out1 <= 32'hxxxxxxxx; ... do something .... ... do something .. end // 可选:添加else分支保持当前值,避免生成不必要的锁存器 end
方式2:拆分变量,分离组合与时序逻辑
如果确实需要保留组合逻辑的部分,通过中间变量隔离组合逻辑和时序逻辑的驱动:
output [31:0] data_out1; reg [31:0] data_out1; reg [31:0] comb_data; // 组合逻辑中间变量 // 组合逻辑块:用阻塞赋值,敏感列表建议用@(*)自动生成 always @(*) begin comb_data = 32'h0; // 设置默认值,避免隐式锁存器 if ((write_mask1 != 32'b0) && (rst_b == 1'b1)) begin comb_data = 32'hxxxxxxxx; ... do something .... end end // 时序逻辑块:同步组合逻辑结果 always @(posedge clk or negedge rst_b) begin if (!rst_b) begin data_out1 <= 32'h0; end else begin data_out1 <= comb_data; // 原时序块中的其他逻辑 ... do something .. end end
额外建议
- 组合逻辑块的敏感列表尽量用
@(*)替代手动列举信号,避免遗漏敏感信号导致的仿真与硬件不一致。 - 所有时序逻辑块统一使用非阻塞赋值,组合逻辑块统一使用阻塞赋值,严格遵循编码规范能避免大部分工具报错和仿真问题。
内容的提问来源于stack exchange,提问作者yongarius
相关产品推荐
相关产品推荐

