FPGA SDR(16)自作FIRフィルタ


2018/07/18 追記:Logic Elementsを節約できるメモリベースFIRフィルタに変更。
2018/07/12 追記:カウンタcntの動作を変更。遮断周波数を変更。

 

ようやく自作FIRフィルタが完成しました。

IP CatalogにあるFIRフィルタは評価版なのでダウンロードケーブルを接続した状態でのみ使うことができます。CICフィルタNCOに続いてFIRフィルタを自作しました。入出力はIP CatalogにあるFIRフィルタに合わせています。

`timescale 1ns/1ns


module MyMEMFIR
#(
	parameter RATE = 1,
	parameter DATA_WIDTH = 10
)
(
	input wire clk,
	input wire reset_n,
	
	input wire signed [DATA_WIDTH-1:0] ast_sink_data,
	input wire ast_sink_valid,
	input wire [1:0] ast_sink_error,

	output reg signed [DATA_WIDTH-1:0] ast_source_data,
	output reg ast_source_valid,
	output wire [1:0] ast_source_error
);


	localparam NUM_TAPS = 99;
	localparam H_WIDTH = 16;
	localparam Y_WIDTH = H_WIDTH + DATA_WIDTH - 1;
	
	
	integer i;

	reg signed [H_WIDTH-1:0] h[0:NUM_TAPS-1];
	wire signed [DATA_WIDTH-1:0] x;
	reg signed [Y_WIDTH-1:0] y;
	
	wire [7:0] raddr;
	wire [7:0] waddr;
	wire wren;
	wire signed [DATA_WIDTH-1:0] data;

	reg [10:0] cnt;
	reg [10:0] deci_cnt;

	
	initial begin
		h[0] = 5;
		h[1] = -5;
		h[2] = 5;
		h[3] = -6;
		h[4] = 6;
		h[5] = -7;
		h[6] = 7;
		h[7] = -8;
		h[8] = 9;
		h[9] = -10;
		h[10] = 11;
		h[11] = -12;
		h[12] = 14;
		h[13] = -15;
		h[14] = 16;
		h[15] = -18;
		h[16] = 20;
		h[17] = -21;
		h[18] = 23;
		h[19] = -25;
		h[20] = 27;
		h[21] = -29;
		h[22] = 30;
		h[23] = -32;
		h[24] = 34;
		h[25] = -36;
		h[26] = 38;
		h[27] = -40;
		h[28] = 42;
		h[29] = -44;
		h[30] = 46;
		h[31] = -47;
		h[32] = 49;
		h[33] = -51;
		h[34] = 53;
		h[35] = -54;
		h[36] = 56;
		h[37] = -57;
		h[38] = 58;
		h[39] = -60;
		h[40] = 61;
		h[41] = -62;
		h[42] = 63;
		h[43] = -63;
		h[44] = 64;
		h[45] = -65;
		h[46] = 65;
		h[47] = -65;
		h[48] = 65;
		h[49] = 32702;
		h[50] = 65;
		h[51] = -65;
		h[52] = 65;
		h[53] = -65;
		h[54] = 64;
		h[55] = -63;
		h[56] = 63;
		h[57] = -62;
		h[58] = 61;
		h[59] = -60;
		h[60] = 58;
		h[61] = -57;
		h[62] = 56;
		h[63] = -54;
		h[64] = 53;
		h[65] = -51;
		h[66] = 49;
		h[67] = -47;
		h[68] = 46;
		h[69] = -44;
		h[70] = 42;
		h[71] = -40;
		h[72] = 38;
		h[73] = -36;
		h[74] = 34;
		h[75] = -32;
		h[76] = 30;
		h[77] = -29;
		h[78] = 27;
		h[79] = -25;
		h[80] = 23;
		h[81] = -21;
		h[82] = 20;
		h[83] = -18;
		h[84] = 16;
		h[85] = -15;
		h[86] = 14;
		h[87] = -12;
		h[88] = 11;
		h[89] = -10;
		h[90] = 9;
		h[91] = -8;
		h[92] = 7;
		h[93] = -7;
		h[94] = 6;
		h[95] = -6;
		h[96] = 5;
		h[97] = -5;
		h[98] = 5;
	end

	
	assign ast_source_error = 2'b00;
	
	always @(posedge clk)
	begin
		if (~reset_n) begin			
			cnt <= 0;
			
			deci_cnt <= 0;
			
			y <= 0;
			ast_source_data <= 0;
			ast_source_valid <= 1'b0;
		end
		else begin
			
			if (ast_sink_valid) begin			
				cnt <= 0;

				y <= 0;
								
				if (deci_cnt == RATE-1) begin
					deci_cnt <= 0;
					
					ast_source_data <= y[Y_WIDTH-1 -: DATA_WIDTH];
					ast_source_valid <= 1'b1;
				end
				else begin
					deci_cnt <= deci_cnt + 1;			
				end
			end
			else begin
				if (cnt <= NUM_TAPS) begin
					cnt <= cnt + 1;
				end
				
				if (1 <= cnt && cnt <= NUM_TAPS) begin
					y <= y + h[NUM_TAPS - cnt] * x;
				end
				
				ast_source_valid <= 1'b0;
			end
		end
	end
	
	assign raddr = NUM_TAPS-1 - cnt;
	assign waddr = (ast_sink_valid) ? 0 : NUM_TAPS - cnt + 1;
	assign wren = (ast_sink_valid || (2 <= cnt && cnt <= NUM_TAPS)) ? 1 : 0;
	assign data = (ast_sink_valid) ? ast_sink_data : x;

	ram16x256 ram16x256_inst (
		.clock (clk),
		.data (data),
		.rdaddress (raddr),
		.wraddress (waddr),
		.wren (wren),
		.q (x)
	);


endmodule