Few years back I wrote a VHDL code for implementing a FIR filter. In this post, I want to implement the same algorithm in Verilog.
Finite Impulse Response(FIR) filters are one of the two main type of filters available for signal processing. As the name suggests the output of a FIR filter is finite and it settles down to zero after some time. For a basic FAQ on FIR filters see this post by dspguru.
A FIR filter output, 'y' can be defined by the following equation:
Here, 'y' is the filter output, 'x' in the input signal and 'b' is the filter coefficients. 'N' is the filter order. The higher the value of N is, the more complex the filter will be.
For writing the code in Verilog I have referred to the paper, VHDL generation of optimized FIR filters. You can say I have coded the exact block diagram available in the paper, "Figure 2".
This is a 4 tap filter. That means the order of the filter is 4 and so it has 4 coefficients. The inputs are chosen to be 8 bits wide and outputs are chosen to be 16 bits wide. Both inputs and outputs can store negative numbers, in two's complement format. If you want to handle inputs with bigger range you can simply increase the size of the inputs and intermediate variables. The structure of the code will remain the same.
The following waveform was obtained in Xilinx ISE 14.6 after successful simulation.
Finite Impulse Response(FIR) filters are one of the two main type of filters available for signal processing. As the name suggests the output of a FIR filter is finite and it settles down to zero after some time. For a basic FAQ on FIR filters see this post by dspguru.
A FIR filter output, 'y' can be defined by the following equation:
For writing the code in Verilog I have referred to the paper, VHDL generation of optimized FIR filters. You can say I have coded the exact block diagram available in the paper, "Figure 2".
This is a 4 tap filter. That means the order of the filter is 4 and so it has 4 coefficients. The inputs are chosen to be 8 bits wide and outputs are chosen to be 16 bits wide. Both inputs and outputs can store negative numbers, in two's complement format. If you want to handle inputs with bigger range you can simply increase the size of the inputs and intermediate variables. The structure of the code will remain the same.
The design contains two files. One is the main file with all the multiplications and adders defined in it, and another one for defining the D flip flop operation.
The codes are given below:
The codes are given below:
fir_4tap:
module fir_4tap(
input Clk,
input signed [7:0] Xin,
output reg signed [15:0] Yout
);
//Internal variables.
wire signed [7:0] H0,H1,H2,H3;
wire signed [15:0] MCM0,MCM1,MCM2,MCM3,add_out1,add_out2,add_out3;
wire signed [15:0] Q1,Q2,Q3;
//filter coefficient initializations.
//H = [-2 -1 3 4].
assign H0 = -2;
assign H1 = -1;
assign H2 = 3;
assign H3 = 4;
//Multiple constant multiplications.
assign MCM3 = H3*Xin;
assign MCM2 = H2*Xin;
assign MCM1 = H1*Xin;
assign MCM0 = H0*Xin;
//adders
assign add_out1 = Q1 + MCM2;
assign add_out2 = Q2 + MCM1;
assign add_out3 = Q3 + MCM0;
//flipflop instantiations (for introducing a delay).
DFF dff1 (.Clk(Clk),.D(MCM3),.Q(Q1));
DFF dff2 (.Clk(Clk),.D(add_out1),.Q(Q2));
DFF dff3 (.Clk(Clk),.D(add_out2),.Q(Q3));
//Assign the last adder output to final output.
always@ (posedge Clk)
Yout <= add_out3;
endmodule
input Clk,
input signed [7:0] Xin,
output reg signed [15:0] Yout
);
//Internal variables.
wire signed [7:0] H0,H1,H2,H3;
wire signed [15:0] MCM0,MCM1,MCM2,MCM3,add_out1,add_out2,add_out3;
wire signed [15:0] Q1,Q2,Q3;
//filter coefficient initializations.
//H = [-2 -1 3 4].
assign H0 = -2;
assign H1 = -1;
assign H2 = 3;
assign H3 = 4;
//Multiple constant multiplications.
assign MCM3 = H3*Xin;
assign MCM2 = H2*Xin;
assign MCM1 = H1*Xin;
assign MCM0 = H0*Xin;
//adders
assign add_out1 = Q1 + MCM2;
assign add_out2 = Q2 + MCM1;
assign add_out3 = Q3 + MCM0;
//flipflop instantiations (for introducing a delay).
DFF dff1 (.Clk(Clk),.D(MCM3),.Q(Q1));
DFF dff2 (.Clk(Clk),.D(add_out1),.Q(Q2));
DFF dff3 (.Clk(Clk),.D(add_out2),.Q(Q3));
//Assign the last adder output to final output.
always@ (posedge Clk)
Yout <= add_out3;
endmodule
DFF:
module DFF
(input Clk,
input [15:0] D,
output reg [15:0] Q
);
always@ (posedge Clk)
Q = D;
endmodule
(input Clk,
input [15:0] D,
output reg [15:0] Q
);
always@ (posedge Clk)
Q = D;
endmodule
Testbench for the FIR filter:
module tb;
// Inputs
reg Clk;
reg signed [7:0] Xin;
// Outputs
wire signed [15:0] Yout;
// Instantiate the Unit Under Test (UUT)
fir_4tap uut (
.Clk(Clk),
.Xin(Xin),
.Yout(Yout)
);
//Generate a clock with 10 ns clock period.
initial Clk = 0;
always #5 Clk =~Clk;
//Initialize and apply the inputs.
initial begin
Xin = 0; #40;
Xin = -3; #10;
Xin = 1; #10;
Xin = 0; #10;
Xin = -2; #10;
Xin = -1; #10;
Xin = 4; #10;
Xin = -5; #10;
Xin = 6; #10;
Xin = 0; #10;
end
endmodule
// Inputs
reg Clk;
reg signed [7:0] Xin;
// Outputs
wire signed [15:0] Yout;
// Instantiate the Unit Under Test (UUT)
fir_4tap uut (
.Clk(Clk),
.Xin(Xin),
.Yout(Yout)
);
//Generate a clock with 10 ns clock period.
initial Clk = 0;
always #5 Clk =~Clk;
//Initialize and apply the inputs.
initial begin
Xin = 0; #40;
Xin = -3; #10;
Xin = 1; #10;
Xin = 0; #10;
Xin = -2; #10;
Xin = -1; #10;
Xin = 4; #10;
Xin = -5; #10;
Xin = 6; #10;
Xin = 0; #10;
end
endmodule
Simulation waveform:
how to add DFF module code to to fir_4tap code? is there any stepts for that?
ReplyDeletecreate a .v file for every module you see above. create a new project and add all the three files to it. the you should be able to compile the codes. Just make sure the compile order is correct. dff first, then fir and then tb.
Deleteis it ok to mention input in integers format( -3,1,-2, etc...)?
ReplyDeleteor it should be in binary format?
you can see the testbench code. As you can see, the inputs can be given in integer format. If you want, the inputs can be given in binary format too.
Deleteok thankyou sir.
DeleteHi,
ReplyDeleteThank you very much for the code. I am trying to implement the 4-tap FIR filter. I have just copied-paste the codes (fir_4tap, DFF and tb) and run simulations on Vivado. I set the Radix to signed decimal, however I get different output for the filter.
The Yout is [-5, -1528, 1267, 1019, 1025, 2299, 1022, 24,0].
I would appreciate if you could advise me what the problem could be?
This comment has been removed by the author.
DeleteThanks for noticing the error. The code had a bug. I have corrected it and uploaded the new code. Please check now.
DeleteDear Mr. Vipin,
DeleteI have tried rewriting my very own verilog code for a 4 tap FIR filter with certain specifications provided on the verilog testbench. I haowever am facing some errors and wanted your help in solving the same. Can you please let me know the best way to contact you?
This comment has been removed by a blog administrator.
ReplyDeletecan i get the code for direct form fir filter in verilog
ReplyDeletecan u plzz use retimming in this filter and write verilog code for that
ReplyDeletehi i'm trying to compare the general multiplier and my idea multiplier with your fir filter code.
ReplyDeleteso i changed your code multiplication and add part to use module and i run the simulation. but begin the Yout have the X values. can you check my code where is the problem? if you can email me ahnk3682@gmail here plz
Is this code is not synthesizable on VIVADO 2014?
ReplyDeletewill u please tell me why i an not able to realize this code on VIVADO 2014.2.
Deleteyes this code is synthesizable on vivado.
Deletehi can you show me the logic gate picture about fir 4tap filter verilog code? i can not understand DFF part.
ReplyDeleteCan you please post the verilog code for IIR filter direct form?
ReplyDeleteare you sure your math is right? and for the DFF should be blocking.
ReplyDeleteGive details about,Tap 10 for filter
ReplyDeletehello please give idea about what is 528MHz frequency is it operation frequency or something else please reply argent is needed
ReplyDelete