Juan Abelaira
Published © GPL3+

FIR filters on FPGA

Design, test and deploy various FIR filters on FPGA with the MYIR development board

IntermediateProtip1 hour789
FIR filters on FPGA

Things used in this project

Hardware components

MYD-CZU3EG
×1

Software apps and online services

Vivado Design Suite
AMD Vivado Design Suite

Story

Read more

Schematics

FIR filters

Code

Chirp file

Verilog
Chirp signal generator
`timescale 1ns / 1ps

module chirp(
		input clk,
		input rst,
		input     [ 9:0] i_step,		// cycles to increase dph
		output reg[ 8:0] o_sig,			// output signal, s0q8
		output    [ 7:0] o_freq			// output f/Fs,   u0q8
    );
    reg  [ 7:0] dph;					// delta ph, phase inc per cycle, u6q2
    reg  [ 8:0] ph;						// phase, u7q2
    reg  [ 9:0] count;
    wire [8:0]sin_table[31:0];			// sin table 0 to pi/2 32 steps s0q8
    
    assign o_freq = dph;				// u0q8 (dph/64)
    
    always @(posedge clk) begin
    	if(rst) begin
    		o_sig <= 0;
    		dph   <= 1;					// 0.25
    		ph    <= 0;
    		count <= 0;
    	end else begin
    		if(count==i_step)begin
    			count <= 0;
    			dph <= dph + 1;
    		end else begin
    			count <= count + 1;
    		end
    		
    		ph <= ph + {1'b0, dph};
    		case(ph[8:7])
    			2'd0: o_sig <= sin_table[ph[6:2]];
    			2'd1: o_sig <= sin_table[31-ph[6:2]];
    			2'd2: o_sig <= -sin_table[ph[6:2]];
    			2'd3: o_sig <= -sin_table[31-ph[6:2]];
    		endcase
    	end
    end
    assign sin_table[0] = 0; 
    assign sin_table[1] = 13; 
    assign sin_table[2] = 25; 
    assign sin_table[3] = 37; 
    assign sin_table[4] = 50;
    assign sin_table[5] = 62; 
    assign sin_table[6] = 74; 
    assign sin_table[7] = 86; 
    assign sin_table[8] = 98; 
    assign sin_table[9] = 109;
    assign sin_table[10] = 120; 
    assign sin_table[11] = 131; 
    assign sin_table[12] = 142; 
    assign sin_table[13] = 152; 
    assign sin_table[14] = 162;
    assign sin_table[15] = 171; 
    assign sin_table[16] = 180; 
    assign sin_table[17] = 189; 
    assign sin_table[18] = 197; 
    assign sin_table[19] = 205;
    assign sin_table[20] = 212; 
    assign sin_table[21] = 219; 
    assign sin_table[22] = 225; 
    assign sin_table[23] = 231; 
    assign sin_table[24] = 236;
    assign sin_table[25] = 240; 
    assign sin_table[26] = 244; 
    assign sin_table[27] = 247; 
    assign sin_table[28] = 250; 
    assign sin_table[29] = 252;
    assign sin_table[30] = 254;
    assign sin_table[31] = 255;

endmodule

fir.v

Verilog
FIR filter
`timescale 1ns / 1ps

module fir(
		input clk,
		input rst,
		input  wire signed[8:0] i_sigin,		// s0q8
		output reg  signed[8:0] o_sigou			// s0q8
    );
    wire signed [29:0] mac  [20:0];
    wire signed [20:0] coeff[20:0];			// s0q20
    
    assign coeff[0] = -82;
    assign coeff[1] = -2309;
	assign coeff[2] = -6683;
	assign coeff[3] = -12087;
	assign coeff[4] = -12624;
	assign coeff[5] = 551;
	assign coeff[6] = 33879;
	assign coeff[7] = 85648;
	assign coeff[8] = 143893;
	assign coeff[9] = 190180;
	assign coeff[10] = 207841;
	assign coeff[11] = 190180;
	assign coeff[12] = 143893;
	assign coeff[13] = 85648;
	assign coeff[14] = 33879;
	assign coeff[15] = 551;
	assign coeff[16] = -12624;
	assign coeff[17] = -12087;
	assign coeff[18] = -6683;
	assign coeff[19] = -2309;
	assign coeff[20] = -82;
	
    genvar i;
    generate
    	for(i=0; i<21; i=i+1) begin
    		if(i==0)begin 
    			fir_stage st_first(	
    				.clk(clk), .rst(rst), .i_x(i_sigin), 
					.i_b(coeff[0]), .i_a(0), .o_mac(mac[0])
				);
    		end else if(i==20) begin
    			fir_stage st_last(	
    				.clk(clk), .rst(rst), .i_x(i_sigin),  
					.i_b(coeff[i]), .i_a(mac[i-1]), .o_mac(mac[i])
				);
    		end else begin 
    			fir_stage st_mid(
    				.clk(clk), .rst(rst), .i_x(i_sigin), 
					.i_b(coeff[i]), .i_a(mac[i-1]), .o_mac(mac[i])
				);
    		end
    	end
    endgenerate
    
    always @(posedge clk) begin
    	if(rst) begin
    		o_sigou <= 0;
    	end else begin
    		o_sigou <= mac[20][29:21];
    	end
    end
endmodule

fir_lp_200_fold.v

Verilog
FIR filter, symmetric
`timescale 1ns / 1ps

module fir_lp_200_fold(
		input clk,
		input rst,
		input  wire signed[8:0] i_sigin,		// s0q8
		output reg  signed[8:0] o_sigou			// s0q8
	);
	wire signed [29:0] macf [100:0];
	wire signed [29:0] macb [100:0];
	wire signed [20:0] coeff[100:0];			// s0q20

// b200=fir1(200,0.2);
assign {
	coeff[0], coeff[1], coeff[2], coeff[3], coeff[4], coeff[5], coeff[6], coeff[7], coeff[8], coeff[9], 
	coeff[10], coeff[11], coeff[12], coeff[13], coeff[14], coeff[15], coeff[16], coeff[17], coeff[18], coeff[19], 
	coeff[20], coeff[21], coeff[22], coeff[23], coeff[24], coeff[25], coeff[26], coeff[27], coeff[28], coeff[29], 
	coeff[30], coeff[31], coeff[32], coeff[33], coeff[34], coeff[35], coeff[36], coeff[37], coeff[38], coeff[39], 
	coeff[40], coeff[41], coeff[42], coeff[43], coeff[44], coeff[45], coeff[46], coeff[47], coeff[48], coeff[49], 
	coeff[50], coeff[51], coeff[52], coeff[53], coeff[54], coeff[55], coeff[56], coeff[57], coeff[58], coeff[59], 
	coeff[60], coeff[61], coeff[62], coeff[63], coeff[64], coeff[65], coeff[66], coeff[67], coeff[68], coeff[69], 
	coeff[70], coeff[71], coeff[72], coeff[73], coeff[74], coeff[75], coeff[76], coeff[77], coeff[78], coeff[79], 
	coeff[80], coeff[81], coeff[82], coeff[83], coeff[84], coeff[85], coeff[86], coeff[87], coeff[88], coeff[89], 
	coeff[90], coeff[91], coeff[92], coeff[93], coeff[94], coeff[95], coeff[96], coeff[97], coeff[98], coeff[99], coeff[100]
} = {
	-21'd79,   -21'd211,   -21'd268,   -21'd225,   -21'd92,    21'd85,   21'd242,   21'd319,    21'd276,    21'd120, 
	-21'd102,  -21'd308,   -21'd416,   -21'd369,   -21'd167,   21'd130,  21'd413,   21'd567,    21'd511,    21'd239, 
	-21'd168,  -21'd561,   -21'd778,   -21'd708,   -21'd340,   21'd215,  21'd755,   21'd1058,   21'd969,    21'd477, 
	-21'd271,  -21'd1001,  -21'd1414,  -21'd1305,  -21'd656,   21'd334,  21'd1304,  21'd1859,   21'd1728,   21'd888, 
	-21'd402,  -21'd1670,  -21'd2404,  -21'd2252,  -21'd1181,  21'd474,  21'd2110,  21'd3069,   21'd2898,   21'd1552, 
	-21'd548,  -21'd2636,  -21'd3877,  -21'd3693,  -21'd2018,  21'd622,  21'd3268,  21'd4865,   21'd4677,   21'd2609, 
	-21'd695,  -21'd4036,  -21'd6088,  -21'd5913,  -21'd3367,  21'd764,  21'd4988,  21'd7635,   21'd7499,   21'd4361, 
	-21'd828,  -21'd6208,  -21'd9660,  -21'd9611,  -21'd5716,  21'd885,  21'd7853,  21'd12455,  21'd12585,  21'd7671, 
	-21'd933,  -21'd10248, -21'd16638, -21'd17156, -21'd10769, 21'd973,  21'd14182, 21'd23787,  21'd25284,  21'd16542, 
	-21'd1001, -21'd22218, -21'd39430, -21'd44551, -21'd31626, 21'd1019, 21'd49727, 21'd105988, 21'd158378, 21'd195466, 21'd208856
};
	genvar i;
	generate
		for(i=0; i<101; i=i+1) begin
			if(i==0)begin 
				fir_stage2 st_ini(
					.clk(clk), .rst(rst), .i_x(i_sigin), .i_b(coeff[i]),
					.i_macf(0), .o_macf(macf[0]), .i_macb(macb[i+1]), .o_macb(macb[i])
				);
			end else if(i < 100) begin
				fir_stage2 st_mid(	
					.clk(clk), .rst(rst), .i_x(i_sigin), .i_b(coeff[i]),
					.i_macf(macf[i-1]), .o_macf(macf[i]), .i_macb(macb[i+1]), .o_macb(macb[i])
				);
			end else begin 
				fir_stage2 st_end(	
				.clk(clk), .rst(rst), .i_x(i_sigin), .i_b(coeff[i]),
				.i_macf(macf[i-1]), .o_macf(macb[i]), .i_macb(0), .o_macb()
			);
			end
		end
	endgenerate

	always @(posedge clk) begin
		if(rst) begin
			o_sigou <= 0;
		end else begin
			o_sigou <= macb[0][28:20];
		end
	end
endmodule

fir_pb_200.v

Verilog
FIR filter, passband
`timescale 1ns / 1ps

module fir_pb_200(
		input clk,
	input rst,
	input  wire signed[8:0] i_sigin,		// s0q8
	output reg  signed[8:0] o_sigou			// s0q8
	);
	wire signed [29:0] macf [100:0];
	wire signed [29:0] macb [100:0];
	wire signed [20:0] coeff[100:0];			// s0q20
	
	// b200=fir1(200,[0.2, 0.3]);
	assign {
		coeff[0], coeff[1], coeff[2], coeff[3], coeff[4], coeff[5], coeff[6], coeff[7], coeff[8], coeff[9], 
		coeff[10], coeff[11], coeff[12], coeff[13], coeff[14], coeff[15], coeff[16], coeff[17], coeff[18], coeff[19], 
		coeff[20], coeff[21], coeff[22], coeff[23], coeff[24], coeff[25], coeff[26], coeff[27], coeff[28], coeff[29], 
		coeff[30], coeff[31], coeff[32], coeff[33], coeff[34], coeff[35], coeff[36], coeff[37], coeff[38], coeff[39], 
		coeff[40], coeff[41], coeff[42], coeff[43], coeff[44], coeff[45], coeff[46], coeff[47], coeff[48], coeff[49], 
		coeff[50], coeff[51], coeff[52], coeff[53], coeff[54], coeff[55], coeff[56], coeff[57], coeff[58], coeff[59], 
		coeff[60], coeff[61], coeff[62], coeff[63], coeff[64], coeff[65], coeff[66], coeff[67], coeff[68], coeff[69], 
		coeff[70], coeff[71], coeff[72], coeff[73], coeff[74], coeff[75], coeff[76], coeff[77], coeff[78], coeff[79], 
		coeff[80], coeff[81], coeff[82], coeff[83], coeff[84], coeff[85], coeff[86], coeff[87], coeff[88], coeff[89], 
		coeff[90], coeff[91], coeff[92], coeff[93], coeff[94], coeff[95], coeff[96], coeff[97], coeff[98], coeff[99], coeff[100]
	} = {
		21'd1, -21'd38, 21'd49, 21'd219, 21'd317, 21'd196, -21'd140, -21'd497, -21'd609, -21'd336, 
		21'd202, 21'd675, 21'd762, 21'd390, -21'd198, -21'd611, -21'd605, -21'd261, 21'd93, 21'd174, 
		21'd1, -21'd117, 21'd114, 21'd640, 21'd1007, 21'd699, -21'd363, -21'd1596, -21'd2085, -21'd1266, 
		21'd539, 21'd2222, 21'd2639, 21'd1465, -21'd516, -21'd1975, -21'd2041, -21'd947, 21'd230, 21'd538, 
		21'd2, -21'd408, 21'd264, 21'd1891, 21'd3095, 21'd2296, -21'd787, -21'd4479, -21'd6098, -21'd3957, 
		21'd1091, 21'd5950, 21'd7376, 21'd4377, -21'd979, -21'd5079, -21'd5491, -21'd2723, 21'd410, 21'd1337, 
		21'd1, -21'd1142, 21'd445, 21'd4603, 21'd7922, 21'd6297, -21'd1252, -21'd10754, -21'd15447, -21'd10760, 
		21'd1649, 21'd14268, 21'd18737, 21'd11964, -21'd1409, -21'd12353, -21'd14216, -21'd7616, 21'd564, 21'd3363, 
		21'd0, -21'd3351, 21'd585, 21'd12359, 21'd23031, 21'd20083, -21'd1579, -21'd32256, -21'd51026, -21'd39712, 
		21'd1997, 21'd52110, 21'd77999, 21'd57989, -21'd1639, -21'd67231, -21'd97506, -21'd70466, 21'd631, 21'd73884, 
		21'd104622
	};
	genvar i;
	generate
	for(i=0; i<101; i=i+1) begin
		if(i==0)begin 
			fir_stage2 st_ini(
				.clk(clk), .rst(rst), .i_x(i_sigin), .i_b(coeff[i]),
				.i_macf(0), .o_macf(macf[0]), .i_macb(macb[i+1]), .o_macb(macb[i])
			);
		end else if(i < 100) begin
			fir_stage2 st_mid(	
				.clk(clk), .rst(rst), .i_x(i_sigin), .i_b(coeff[i]),
				.i_macf(macf[i-1]), .o_macf(macf[i]), .i_macb(macb[i+1]), .o_macb(macb[i])
			);
		end else begin 
			fir_stage2 st_end(	
			.clk(clk), .rst(rst), .i_x(i_sigin), .i_b(coeff[i]),
			.i_macf(macf[i-1]), .o_macf(macb[i]), .i_macb(0), .o_macb()
		);
		end
	end
	endgenerate
	
	always @(posedge clk) begin
		if(rst) begin
			o_sigou <= 0;
		end else begin
			o_sigou <= macb[0][28:20];
		end
	end
endmodule

fir_stage.v

Verilog
FIR stage, non symmetric
`timescale 1ns / 1ps

module fir_stage(
    input clk,
    input rst,
    input wire signed[8:0] i_x,
    input wire signed[20:0] i_b,
    input wire signed[29:0] i_a,
    output reg signed[29:0] o_mac
    );
    
    wire [29:0] prod;
    
    assign prod = (i_x * i_b);
    
    always @(posedge clk) begin
    	if (rst) begin
    		o_mac  <= 0;
    	end else begin
    		o_mac  <= i_a + prod;
    	end
    end
endmodule

fir_stage2.v

Verilog
FIR stage, symmetric
`timescale 1ns / 1ps

module fir_stage2(
		input  clk,
		input  rst,
		input  wire signed [ 8:0] i_x,
		input  wire signed [20:0] i_b,
		input  wire signed [29:0] i_macf,
		input  wire signed [29:0] i_macb,
		output reg signed [29:0] o_macf,
		output reg signed [29:0] o_macb
    );
    
    //wire [29:0] prod;
    
    //assign prod = i_x*i_b;
    
    always @(posedge clk) begin
    	if(rst) begin
    	
    	end else begin
    		o_macf <= i_macf + i_x*i_b;
    		o_macb <= i_macb + i_x*i_b;
    	end
    end
endmodule

Credits

Juan Abelaira
12 projects • 27 followers
Electronics engineer focused on FPGA for accelerated computing and ML but with a wide background in electronics design and software design

Comments