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 thecurrout
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:
- [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
- [Constraints 18-5210] No constraint will be written out.
In short, these were benign warnings, as far as I can tell.