Search code examples
verilogsimulationsystem-verilogfpgasynthesis

Start up behavior of moving average filter is different between pre and post synthesis functional simulation


I've implemented a moving average filter (in Verilog), based on an article I read which performs differently pre and post synthesis. The design implements $y[n]=y[n-1]+x[n]-x[N-1]$.

module ma_width #(parameter WIDTH =16)(
    new_sample,
    en,
    sample_out, 
    clk,
    reset_b
    );

input   [15:0]  new_sample;
input   en;
input   clk;
input   reset_b;          //active low reset
output reg  [15:0]  sample_out;



 // ex. adding 16 16-bit numbers requires 20bits...

(*keep="true"*) reg [15:0]sample_in_fifo[0:WIDTH-1];

// use generate to create fifo as a chain of sixteen 16-bit registers

genvar i;
generate
     for (i = 0; i < WIDTH-1 ; i = i + 1) begin: gd
         always @(posedge clk) begin
            if(!reset_b)
            begin
                sample_in_fifo[i+1] <=4'h0000 ;
            end
            else if (en)
            begin
                sample_in_fifo[i+1] <= sample_in_fifo[i];
            end
         end
    end
endgenerate

always @(posedge clk) begin
    if(!reset_b)
    begin
        sample_in_fifo[0]<=4'h0000;
    end
    else if (en)
    begin
        sample_in_fifo[0] <= new_sample;
    end
end

(*keep = "true"*)reg  [19:0]prevout;
(*keep = "true"*)wire [19:0] currout;

assign currout = prevout + {4'b0000,new_sample} - {4'b0000,sample_in_fifo[WIDTH-1]}; 

always @(posedge clk) begin
    if (!reset_b)
    begin
        sample_out <= 16'h0000;
        prevout <= 20'h00000;
    end
    else if (en)
    begin
       sample_out <= currout[19:4]; //divide by 16
       prevout[19:0] <= currout[19:0];  //but don't lose precision....
    end
end

endmodule

I've run into two issues:

  1. prevout was being synthesized down from a [19:0] register to a [3:0] register -I got around this by using the "keep" synthesis directive --but I'm not sure why it was being synthesized "out" like that ---I'm sure that is a clue to the other anomaly I'm seeing.

  2. In the simulation, I expect prevout to latch the state of the currout signal prior to the rising clock edge. However, for some reason, this is not the case until about 6 clock cycles, after which it then behaves as expected:

POST SYNTH SIM: updated Post synth sim

At this point I'm baffled w.r.t. to what synthesizer is doing. This works fine in the behavioral simulation, and I can't figure out what in the code (always blocks) may be ambiguously defining the registers or the logic to "confuse" or mislead the synthesizer. Any pointers on how to approach debugging this would help a lot.

In effect, the moving average filter does do what it is supposed to, except at start up. And, since I don't understand what is happening at start up, it makes me not trust the design/synthesis/and perhaps the implementation fully.

Pre-synth SIM below: enter image description here

per request in the comments, i'm including the 2 warnings (there were no errors) obtained from synthesis:

  1. [Synth 8-2507] parameter declaration becomes local in ma_width with formal parameter declaration list ["C:/Users/jorge.rive/ClampPWM/Vivado/cip_repo/ma-width/ma_width.v":44]

this is due to a parameter definintion, but it isn't used, so ignore. and

  1. [Constraints 18-5210] No constraint will be written out.

In short, these were benign warnings, as far as I can tell.


Solution

  • A possibility is that the entire part is held in reset by a hardware global reset built into the hardware/fabric for some number of clocks or some amount of time.

    Try delaying the stimulus and user reset for 10 clocks to test this theory.

    I have seen stuff like this where there are resets in hardware that are not well understood without some deep drilling.

    Post-synthesis simulations execute the vendors simulation model (the users RTL that has been targeted to a vendor model by synthesis) rather than the users RTL.
    It can behave in ways not known to the user.