Verilog中@(posedge clk)实现valid_dat单周期延迟失效问题排查
问题描述
我尝试用@(posedge clk)给valid_dat信号引入单周期延迟,但功能未生效。计数器能正常随每个时钟周期自增1,可valid_delay信号却和valid_dat同步变化,请求协助排查原因。
相关Verilog代码
// Butterfly // 1. U <- (X + Y MOD) P // 2. V <- ((X - Y) * W * INV) MOD P // Macro for number of input data, `width groups = 2 x `width numbers in total `define width 4 // Top-Level Design module BF #(parameter inv = 256'h8fac2de6599e1a9fa53ddf925918fe6fff2d6e9209dacc5e13f75b68fe75c041, M = 256'h73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001, Mp = 256'h3d443ab0d7bf2839181b2c170004ec0653ba5bfffffe5bfdfffffffeffffffff ) (input clk, input nrst, input valid_dat, input valid_tw, input[255:0] dat_in, output valid_out, output [255:0] dat_out, output calc_done); localparam wd = $clog2(`width); localparam state_rst = 3'b000, state_ld = 3'b001, state_sub = 3'b010, state_mont = 3'b011, state_out = 3'b100, state_done = 3'b101, state_halt = 3'b111; // Indicators reg pkt_end; reg pkt_start, valid_delay; // For loop index integer i; //Buffers reg [255:0] A_buffer[`width-1:0], B_buffer[`width-1:0], TW_buffer[`width-1:0], U_buffer[`width-1:0], V_buffer[`width-1:0]; // Counters reg [wd-1:0] cnt_tw, cnt_calc; reg [wd:0] cnt_dat, cnt_out; // Start signals reg AddStart, SubStart, MontStart; // Component Inputs wire [255:0] AddA, AddB, SubA, SubB, MontA, MontB; // Component Outpus -- Busy/Done signals wire AddBusy, AddDone, SubBusy, SubDone, MontBusy, MontDone; // Component Outpus -- Calculation results wire [255:0] AddC, SubC, MontC; // Outputs reg valid_out_s; reg calc_done_s; reg [255:0] dat_out_s; // Control Unit state reg [2:0] state; //test reg [255:0] dat_test; // Instantiation of Calculation components Mont256 #(.inv(inv), .M(M), .Mp(Mp)) mont (.clk(clk), .start(MontStart), .A(MontA), .B(MontB), .busy(MontBusy), .done(MontDone), .C(MontC)); Add256 #(.M(M)) add (.clk(clk), .start(SubStart), .A(AddA), .B(AddB), .busy(AddBusy), .done(AddDone), .C(AddC)); Sub256 #(.M(M)) sub (.clk(clk), .start(SubStart), .A(SubA), .B(SubB), .busy(SubBusy), .done(SubDone), .C(SubC)); // Indicators always @(posedge clk or negedge nrst) begin if (!nrst) begin valid_delay <= 0; end else begin valid_delay <= valid_dat; end end always @(*) begin if (state == state_ld && cnt_tw == `width/2 && cnt_dat == `width) begin pkt_end <= 1; end else begin pkt_end <= 0; end end // Counters always @(posedge clk or pkt_start) begin if (pkt_start) begin cnt_dat <= 0; cnt_tw <= 0; cnt_calc <= 0; cnt_out <= 0; end else begin if (valid_dat) begin cnt_dat <= cnt_dat + 1; end if (valid_tw) begin cnt_tw <= cnt_tw + 1; end if (MontDone) begin cnt_calc <= cnt_calc + 1; end if (state == state_out) begin cnt_out <= cnt_out + 1; end end end // Input Buffers always @(cnt_dat or MontDone) begin // Note to readers: this may cause issues to on board testing since we don't know the status of cnt_dat when its not reset // but it should be working for the simulation. if (valid_dat) begin if (cnt_dat[0] == 0) begin for (i=1;i<`width;i=i+1) begin A_buffer[i] <= A_buffer[i-1]; A_buffer[0] <= dat_in; end end else begin if (cnt_dat[0] == 1) begin for (i=1; i<`width; i=i+1) begin B_buffer[i] <= B_buffer[i-1]; B_buffer[0] <= dat_in; end end end end if (MontDone) begin for (i=1;i<`width;i=i+1) begin A_buffer[i] <= A_buffer[i-1]; A_buffer[0] <= '0; B_buffer[i] <= B_buffer[i-1]; B_buffer[0] <= '0; end end end always @(cnt_tw or MontDone) begin // Note to readers: this may cause issues to on board testing since we don't know the status of cnt_tw when its not reset // but it should be working for the simulation. if (valid_tw) begin for (i=1; i<`width; i=i+1) begin TW_buffer[i] <= TW_buffer[i-1]; TW_buffer[0] <= dat_in; end end if (MontDone) begin for (i=1;i<`width;i=i+1) begin TW_buffer[i] <= TW_buffer[i-1]; TW_buffer[0] <= '0; end end end // Inputs for Adder, Subtractor and Multiplier assign AddA = A_buffer[`width-1]; assign AddB = B_buffer[`width-1]; assign SubA = A_buffer[`width-1]; assign SubB = B_buffer[`width-1]; assign MontA = SubC; assign MontB = TW_buffer[`width-1]; // Control Unit always @(posedge clk or pkt_start or negedge nrst) begin if (!nrst) begin valid_out_s <= 0; calc_done_s <= 0; state <= state_rst; AddStart <= 0; SubStart <= 0; MontStart <= 0; end else begin if (state == state_rst) begin if (pkt_start == 1) begin state <= state_ld; end end if (state == state_ld) begin if (pkt_end == 1) begin state <= state_sub; AddStart <= 1; SubStart <= 1; MontStart <= 0; end end if (state == state_sub) begin if (SubDone == 1) begin state <= state_mont; SubStart <= 0; MontStart <= 1; end end if (state == state_mont) begin if (MontDone == 1 && cnt_calc == '1) begin state <= state_out; SubStart <= 0; MontStart <= 0; valid_out_s <= 1; end else begin if (MontDone == 1 && cnt_calc != '1) begin state <= state_sub; SubStart <= 1; MontStart <= 0; end else begin state <= state_mont; SubStart <= 0; MontStart <= 1; end end end if (state == state_out) begin if (cnt_out == 2*`width-2) begin calc_done_s <= 1; end if (cnt_out == '1) begin state <= state_done; calc_done_s <= 0; valid_out_s <= 0; end else begin state <= state_out; end end if (state == state_done) begin state <= state_done; end end end // Output Buffers always @(AddDone) begin if (AddDone) begin for (i=1;i<`width;i=i+1) begin U_buffer[i] <= U_buffer[i-1]; U_buffer[0] <= AddC; end end end always @(MontDone) begin if (MontDone) begin for (i=1;i<`width;i=i+1) begin V_buffer[i] <= V_buffer[i-1]; V_buffer[0] <= MontC; end end end always @(posedge clk) begin if (valid_out_s == 1 && cnt_out[0] == 0) begin for (i=1;i<`width;i=i+1) begin U_buffer[i] <= U_buffer[i-1]; U_buffer[0] <= '0; end end if (valid_out_s == 1 && cnt_out[0] == 1) begin for (i=1;i<`width;i=i+1) begin V_buffer[i] <= V_buffer[i-1]; V_buffer[0] <= '0; end end end // Outuputs always @(*) begin if (valid_out_s == 1 && cnt_out[0] == 0) begin dat_out_s <= U_buffer[`width-1]; end else begin if (valid_out_s == 1 && cnt_out[0] == 1) begin dat_out_s <= V_buffer[`width-1]; end else begin dat_out_s <= '0; end end end assign dat_out = dat_out_s; assign valid_out = valid_out_s; assign calc_done = calc_done_s; endmodule
波形图

排查分析与解决办法
从代码和波形来看,valid_delay的寄存器逻辑本身是正确的,出现同步问题大概率是以下几个原因:
仿真采样显示问题
多数仿真工具默认在时钟上升沿时刻采样信号。如果valid_dat是在时钟上升沿同时变化(比如由组合逻辑生成,或与时钟同步但无严格时序约束),仿真波形会显示valid_delay和valid_dat同步变化,但实际硬件中valid_delay确实是延迟一个周期的。可以检查波形的时间刻度,放大时钟沿附近的细节,看是否存在微小的时序差。valid_dat的来源问题
如果valid_dat是上游模块用同一时钟的寄存器输出,那么在当前模块的时钟上升沿,valid_dat的新值刚稳定,valid_delay会在下一个周期捕获到该值。但如果valid_dat是组合逻辑直接驱动,没有经过寄存器同步,就会出现和valid_delay视觉上同步的情况。建议上游模块先将valid_dat打一拍再输出。未知状态干扰
代码中pkt_start是reg类型但未在复位或任何逻辑中初始化,初始值不确定。虽然它和valid_delay没有直接关联,但未知状态可能影响整体仿真环境,建议在复位逻辑中添加pkt_start <= 0;来消除潜在干扰。验证与修复步骤
- 添加二级延迟验证寄存器逻辑:
观察reg valid_delay2; always @(posedge clk or negedge nrst) begin if (!nrst) begin valid_delay2 <= 0; end else begin valid_delay2 <= valid_delay; end endvalid_delay2是否比valid_delay延迟一个周期,以此确认寄存器打拍逻辑是否正常。 - 调整仿真采样设置:将仿真工具的采样时间改为时钟上升沿之后的ns级(比如1ns),查看是否能显示出
valid_delay与valid_dat的时序差。 - 同步
valid_dat来源:如果valid_dat是组合逻辑输出,在上游模块用寄存器打一拍后再输入到当前BF模块。
- 添加二级延迟验证寄存器逻辑:
内容的提问来源于stack exchange,提问作者user22714606
相关产品推荐
相关产品推荐

