Verilog累加器代码无报错但无输出结果问题排查求助
Problem Description
I'm working on a Verilog accumulator where:
- I generate a pseudorandom signal, convert it from 0-1 range to a signed -1-1 range to get the
acminsignal, then accumulate it. - The debugger throws no errors, but I can't see any results from the accumulator
acc. - My goal is to accumulate
acminon both the rising and falling edges of the clock.
Here's my design and testbench code:
Design Module
module lfsr(clk, rst, seed, load, R, acc); input [3:0] R; input [26:0] seed; input load; input rst; input clk; reg [3:0]q; wire [3:0] S; wire overflow; wire [3:0] acmin ; wire [26:0] state_out; wire [26:0] state_in; output [7:0] acc; reg [7:0] acc; flipflop F[26:0] (state_out, clk, rst, state_in); mux M1[26:0] (state_in, load, seed, {state_out[25],state_out[24],state_out[23],state_out[22],state_out[21],state_out[20],state_out[19],state_out[18],state_out[17],state_out[16],state_out[15],state_out[14],state_out[13],state_out[12],state_out[11],state_out[10],state_out[9],state_out[8],state_out[7],state_out[6],state_out[5],state_out[4],state_out[3],state_out[2], state_out[1], state_out[0], nextbit}); xor G1(nextbit, state_out[5], state_out[2], state_out[1], state_out[26]); // Pseudorandom generator always@(clk) begin if (state_out[26]==0) q=4'b1111; // 0 to -1 else q=4'b0001; //1 to 1 end assign acmin= R*q; // accumulator input always@(clk) begin if(rst) acc = 8'b00000000; else acc = acc + acmin; end endmodule
Testbench
module lfsrtst; reg [3:0] R; reg clk; reg rst; reg [26:0] seed; reg load; wire [7:0] acc; lfsr lfsr(clk, rst, seed, load, R, acc); initial begin clk = 0; load = 0; seed = 0; rst = 0; R=0; #10 rst = 1; #10 rst = 0; #50 R = 4'b0111; #50 R = 4'b0010; #100 R = 4'b1111; #50 R = 4'b1011; #150 R = 4'b1101; #50 R = 4'b1000; end // drive clock always #50 clk = !clk; // program lfsr initial begin #100 seed = 27'b000000110000011000001000001; load = 1; #100 load = 0; #1400 $stop; end endmodule
I'm getting the expected acmin signal, but acc shows no results. What's wrong here?
Root Cause Analysis
There are three critical issues preventing acc from working correctly:
1. Reset Logic Isn't Triggered When Needed
Your accumulator's always block only listens for clk changes in its sensitivity list, but rst is excluded. In your testbench, rst goes high then low before the clock ever toggles (clock first flips at #50, while rst changes at #10 and #20). This means the reset assignment if(rst) acc = 8'b0; never runs, leaving acc stuck in its initial unknown state (x). Any addition with x will just keep acc as x, so you'll never see valid output.
2. Unsigned/Signed Mismatch Breaks acmin Calculation
You intend q to represent -1 or 1, but both q and R are declared as unsigned (reg [3:0]). When you do R*q, Verilog performs unsigned multiplication:
4'b1111as an unsigned value is 15, not-1- This makes
acmincompletely different from what you expect, even ifaccdid work.
3. Dual-Edge Trigger Implementation Is Ambiguous
While always@(clk) will trigger on both clock edges, it's not explicit, and combining it with an unlisted reset signal creates unpredictable behavior. It's better to explicitly define the sensitivity list for dual-edge triggering.
Fixed Code
Updated Design Module
module lfsr(clk, rst, seed, load, R, acc); input signed [3:0] R; // Mark as signed for correct arithmetic input [26:0] seed; input load; input rst; input clk; reg signed [3:0] q; // Signed to represent -1/1 correctly wire [3:0] S; wire overflow; wire signed [3:0] acmin ; // Signed output from multiplication wire [26:0] state_out; wire [26:0] state_in; output signed [7:0] acc; // Signed accumulator for negative values reg signed [7:0] acc; flipflop F[26:0] (state_out, clk, rst, state_in); // Simplified concatenation for readability mux M1[26:0] (state_in, load, seed, {state_out[25:0], nextbit}); xor G1(nextbit, state_out[5], state_out[2], state_out[1], state_out[26]); // Pseudorandom generator with explicit signed values always@(*) begin if (state_out[26] == 0) q = -4'sd1; // Clearer way to write signed -1 else q = 4'sd1; // Clearer way to write signed 1 end assign acmin = R * q; // Now performs signed multiplication as intended // Dual-edge triggered accumulator with asynchronous reset always@(posedge clk or negedge clk or posedge rst) begin if(rst) acc = 8'sd0; // Reset to signed 0 else acc = acc + acmin; // Signed accumulation end endmodule
Updated Testbench
module lfsrtst; reg signed [3:0] R; // Match signed type from design reg clk; reg rst; reg [26:0] seed; reg load; wire signed [7:0] acc; lfsr lfsr(clk, rst, seed, load, R, acc); initial begin clk = 0; load = 0; seed = 0; rst = 0; R = 0; #10 rst = 1; #10 rst = 0; #50 R = 4'sd7; // Signed 7 (matches 4'b0111) #50 R = 4'sd2; // Signed 2 (matches 4'b0010) #100 R = -4'sd1; // Explicit signed -1 (matches 4'b1111) #50 R = -4'sd5; // Signed -5 (matches 4'b1011) #150 R = -4'sd3; // Signed -3 (matches 4'b1101) #50 R = -4'sd8; // Signed -8 (matches 4'b1000) end // Clock with 50ns total period (triggers twice per cycle for dual-edge) always #25 clk = !clk; // Load LFSR seed initial begin #100 seed = 27'b000000110000011000001000001; load = 1; #100 load = 0; #1400 $stop; end endmodule
Key Changes Explained
- Sensitivity List Fix: The accumulator's
alwayslist now includesposedge clk,negedge clk, andposedge rst, ensuring reset triggers immediately and both clock edges trigger accumulation. - Signed Type Declarations: All relevant signals are marked
signedto ensure multiplication and accumulation behave as intended for negative values. - Clearer Value Assignments: Using
-4'sd1instead of4'b1111makes the intent of representing-1explicit, avoiding unsigned/signed confusion. - Clock Adjustment: The testbench clock now toggles every 25ns (50ns total period), so each cycle triggers accumulation twice (once on rising, once on falling edge) as you requested.
内容的提问来源于stack exchange,提问作者Derun Karabeyoglu

