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:
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.
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:
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.
per request in the comments, i'm including the 2 warnings (there were no errors) obtained from synthesis:
this is due to a parameter definintion, but it isn't used, so ignore. and
In short, these were benign warnings, as far as I can tell.
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.