HDLBits边缘检测:两种Verilog实现为何行为存在差异?
我在HDLBits上进行Verilog边缘检测练习时,对if ({d_last, in} == 2'b01)与pedge <= in & ~d_last这两种写法的行为差异感到困惑——二者看起来都是对比当前与前一周期的信号,为什么我的代码会报出输出固定电平的警告?
我的代码
module top_module ( input clk, input [7:0] in, output [7:0] pedge ); reg [7:0] d_last; always @(posedge clk) begin d_last <= in; if ({d_last, in} == 2'b01) pedge <= 1; else pedge <= 0; end endmodule
警告信息
Warning (13024): Output pins are stuck at VCC or GND
该警告表示输出引脚始终固定为高电平(VCC)或低电平(GND)。若输出引脚不应为常量,这可能意味着存在bug,例如赋值语句导致值始终不变(如assign a = x & ~x;)。
官方解决方案
module top_module( input clk, input [7:0] in, output reg [7:0] pedge); reg [7:0] d_last; always @(posedge clk) begin d_last <= in; // 记录前一周期的输入状态 pedge <= in & ~d_last; // 当输入从0变为1时,检测到上升沿 end endmodule
差异原因解析
1. 位宽匹配错误
你的代码中,{d_last, in}是将两个8位信号拼接成16位宽的信号,然后和2位的2'b01做比较。Verilog中不同位宽的信号比较时,会将短位宽的信号零扩展到长位宽的长度,也就是2'b01会被扩展为16'b0000000000000001。这意味着只有当d_last的8位全为0,且in只有最低位为1、其余7位全为0时,条件才会成立——这种场景几乎不会出现,导致pedge绝大多数时候被赋值为0,综合器因此判定输出固定为低电平,抛出警告。
另外,你给8位的pedge赋值为1,会被自动扩展为8'b00000001,这也不符合需求:我们需要对in的每一位单独检测上升沿,而不是只把最低位置1。
2. 逻辑粒度错误
官方代码的in & ~d_last是对每一位单独进行上升沿检测:对于in的每一位,当当前周期为1、前一周期为0时,对应位输出1,否则输出0,完美实现了8位信号的逐位上升沿检测。
而你的代码用拼接后的整体信号做判断,本质是把两个8位信号当成一个16位信号来处理,完全误解了逐位检测的需求,逻辑上从根就错了。
3. 输出类型声明遗漏
你的代码中pedge是output [7:0]类型,但在always块中赋值,Verilog要求这类输出必须声明为reg类型(如官方代码中的output reg [7:0] pedge),否则会引发隐含的类型不匹配问题,也可能加剧综合器的误判。
内容的提问来源于stack exchange,提问作者xiumpt

