FPGA SDR(12)自作CICフィルタ


2018/07/29 追記:パラメータを変更しました。
2018/07/05 追記:段数が増えると出力レベルが下がる不具合を直しました。

 

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

MegaWizardのCICフィルタの生成が途中で止まってしまうEP2C5T144でもこの自作フィルタなら使用できます。

`timescale 1ns/1ns


module MyCIC
 #(
	parameter NUM_STAGES = 3,
	parameter MAX_RATE_WIDTH = 12,
	parameter DATA_WIDTH = 19
 )
(
	input wire clk,
	input wire reset_n,
	input wire [MAX_RATE_WIDTH:0] rate,
	
	input wire signed [DATA_WIDTH-1:0] in_data,
	output wire in_ready,
	input wire in_valid,
	input wire [1:0] in_error,

	output reg signed [DATA_WIDTH-1:0] out_data,
	input wire out_ready,
	output reg out_valid,
	output wire [1:0] out_error
);


	localparam WIDTH = MAX_RATE_WIDTH * NUM_STAGES + DATA_WIDTH;
	
	integer i;

	reg signed [WIDTH-1:0] integ [0:NUM_STAGES];
	reg signed [WIDTH-1:0] diff [0:NUM_STAGES];
	reg signed [WIDTH-1:0] diff_d [0:NUM_STAGES];

	reg [MAX_RATE_WIDTH:0] count;
	reg [3:0] rate_width;
	reg next_out_valid;

	
	assign in_ready = 1'b1;
	assign out_error = 2'b00;
	
	always @(posedge clk)
	begin
		if (~reset_n)
		begin
			for (i = 1; i <= NUM_STAGES; i = i + 1) begin
				integ[i] <= 0;
			end
			
			diff[1] <= 0;
		end else
		begin
			integ[1] <= in_data + integ[1];
			
			for (i = 2; i <= NUM_STAGES; i = i + 1) begin
				integ[i] <= integ[i-1] + integ[i];
			end
			
			diff[1] <= integ[NUM_STAGES-1] + integ[NUM_STAGES];
		end
	end
	
	always @(posedge clk)
	begin
		if (~reset_n)
		begin
			count <= 0;
			next_out_valid <= 1'b1;
			
			rate_width <= 0;
		end else
		begin			
			if (count == rate - 1)
			begin
				count <= 0;
				next_out_valid <= 1'b1;
				
				if      (count >= 16384) rate_width <= 15;
				else if (count >= 8192) rate_width <= 14;
				else if (count >= 4096) rate_width <= 13;
				else if (count >= 2048) rate_width <= 12;
				else if (count >= 1024) rate_width <= 11;
				else if (count >= 512) rate_width <= 10;
				else if (count >= 256) rate_width <= 9;
				else if (count >= 128) rate_width <= 8;
				else if (count >= 64) rate_width <= 7;
				else if (count >= 32) rate_width <= 6;
				else if (count >= 16) rate_width <= 5;
				else if (count >= 8) rate_width <= 4;
				else if (count >= 4) rate_width <= 3;
				else if (count >= 2) rate_width <= 2;
				else if (count >= 1) rate_width <= 1;
				else rate_width <= 0;
			end else
			begin
				count <= count + 1;
				next_out_valid <= 1'b0;
			end
		end
	end
	
	always @(posedge clk)
	begin
		out_valid <= next_out_valid;
		
		if (~reset_n)
		begin
			for (i = 1; i <= NUM_STAGES; i = i + 1) begin
				diff_d[i] <= 0;
			end
			
			for (i = 2; i <= NUM_STAGES; i = i + 1) begin
				diff[i] <= 0;
			end
			
			out_data <= 0;
		end else
		begin
			if (next_out_valid)
			begin
				for (i = 1; i <= NUM_STAGES; i = i + 1) begin
					diff_d[i] <= diff[i];
				end
			
				for (i = 2; i <= NUM_STAGES; i = i + 1) begin
					diff[i] <= diff[i-1] - diff_d[i-1];
				end
								
				out_data <= (diff[NUM_STAGES] - diff_d[NUM_STAGES]) >>> (rate_width * NUM_STAGES);
			end
		end
	end
	
endmodule

IP CatalogにあるCICフィルタは cic の代わりに自作CICフィルタ MyCIC を使うことができます。

	cic cic_inst_i (
		...
	);

	cic cic_inst_q (
		...
	);
	MyCIC cic_inst_i (
		...
	);

	MyCIC cic_inst_q (
		...
	);

一度評価版のIPを追加したQuartusプロジェクトは評価版のIPを削除してもダウンロード状態でしか動作しません。自作CICフィルタと自作NCOを使ってプロジェクトを作り直す必要があります。