I have a fir filter implementation in Verilog and I don't understand y <= (y_n >> 16);
. This is the most straightforward implementation, directly form the fir equation(direct form design).
module fir1
#(parameter N=32)
(
input clk,
input rst_n,
input enable,
input [N-1:0]x,
output reg busy,
output reg valid,
output reg [N-1:0]y
);
localparam IDLE = 0,
EVA = 1;
reg [N-1:0] y_n;
reg [5:0] state, state_n;
reg [5:0] cnt, cnt_n;
reg valid_n;
reg busy_n;
integer i, j;
always@*
begin
case(state)
IDLE : state_n = enable ? EVA : IDLE;
EVA : state_n = enable ? EVA : IDLE;
default : state_n = IDLE;
endcase
end
always@*
begin
if(state == EVA)
if(cnt == 16)
cnt_n = cnt;
else
cnt_n = cnt + 1;
else
cnt_n = 0;
end
always@*
begin
if((state == EVA) & (cnt == 16))
valid_n = 1;
else
valid_n = 0;
end
always@*
begin
if(state == EVA)
busy_n = 0;
else
busy_n = 0;
end
wire [32-1:0] num [0:15];
reg [N-1:0] x_val [0:15];
assign num[0] = -32'd157;
assign num[1] = 32'd380;
assign num[2] = -32'd399;
assign num[3] = -32'd838;
assign num[4] = 32'd3466;
assign num[5] = -32'd4548;
assign num[6] = -32'd1987;
assign num[7] = 32'd36857;
assign num[8] = 32'd36857;
assign num[9] = -32'd1987;
assign num[10] = -32'd4548;
assign num[11] = 32'd3466;
assign num[12] = -32'd838;
assign num[13] = -32'd399;
assign num[14] = 32'd380;
assign num[15] = -32'd157;
always @* begin
y_n = 0;
for (j = 0; j <= 15; j = j + 1) begin
y_n = y_n + (x_val[j] * num[j]);
end
end
always@(posedge clk)
begin
if(~rst_n)begin
state <= IDLE;
cnt <= 0;
valid <= 0;
busy <= 0;
y <= 1534;
for (i = 0; i < 16; i = i + 1)
x_val[i] <= 0;
end
else begin
state <= state_n;
cnt <= cnt_n;
valid <= valid_n;
busy <= busy_n;
y <= (y_n >> 16); //This line I don't understand
x_val[15] <= x_val[14];
x_val[14] <= x_val[13];
x_val[13] <= x_val[12];
x_val[12] <= x_val[11];
x_val[11] <= x_val[10];
x_val[10] <= x_val[9];
x_val[9] <= x_val[8];
x_val[8] <= x_val[7];
x_val[7] <= x_val[6];
x_val[6] <= x_val[5];
x_val[5] <= x_val[4];
x_val[4] <= x_val[3];
x_val[3] <= x_val[2];
x_val[2] <= x_val[1];
x_val[1] <= x_val[0];
x_val[0] <= x; // input signal shift in the fir filter.
end
end
endmodule
I have checked the testbench, and it works fine. But, I still don't understand the logical shift operation.
The line y <= (y_n >> 16);
is shifting the filter output to the right 16 times.
The reason for this is scaling the result to fit in a 32 bit output vector.
The general topic is called bit growth.
A reference for bit growth in fpga arithmetic: Zip CPU Bit Growth
In an FIR the input signal is multiplied by a constant which creates a new signal which is 32 bits times 32 bits = 64 bits to completely contain the result of the multiply. That 64 bit vector is added to similar vector 16 times which requires an extra 4 bits to contain. To completely hold the maximum possible value would occupy 64 + 4 = 68 bits. If the system needs a 32 bit output, then the internal signal must be trimmed to fit. The designer has decided to accomplish the trimming by shifting right 16 times and loosing the precision of the 16 lsb's.
Without scaling (shift right by 16 places in this case), the output must be 68 bits wide to contain the maximum possible accumulation of all 16 taps.
There are inconsistencies in the choice of the bit widths here because y_n is only 32 bits. The input data times the coefficients must be known to occupy 32 bits for this filter. Variable y_n needs to be 68 bits for random data that occupied 32 bits at the input, and 32 bit coefficients. All the bit width numbers change if you know that the input data in constrained to be less than the maximum size which could be represented by the input vector. It looks like the input must be something like 16 bits contained in a 32 bit Verilog vector (I don't know what the data is since you have not provided that info; it just looks like the filter is designed to handle less dynamic range than is possible in 32 bits).