blob: 554f536aab4d1268baebdedbc679b3c16787062e [file] [log] [blame]
// altera verilog_input_version SystemVerilog_2005
/*
Legal Notice: (C)2007 Altera Corporation. All rights reserved. Your
use of Altera Corporation's design tools, logic functions and other
software and tools, and its AMPP partner logic functions, and any
output files any of the foregoing (including device programming or
simulation files), and any associated documentation or information are
expressly subject to the terms and conditions of the Altera Program
License Subscription Agreement or other applicable license agreement,
including, without limitation, that your use is for the sole purpose
of programming logic devices manufactured by Altera and sold by Altera
or its authorized distributors. Please refer to the applicable
agreement for further details.
*/
/*
Author: JCJB
Date: 01/28/2008
This block contains a FIR filter capable of the following:
- 4/8/16 symetrical taps
- parameterizable FIFO depth
- Avalon-ST integration
This hardware has not been optimized for targeting DSP blocks
or memory. It is recommended to replace the multipliers with
memory multiplications.
The register "tag" is used to perform flow control to avoid overflowing
the output FIFO. For every data sample that enters the filter, five clock
cycles of latency will occur before the result is stuffed into the FIFO.
If the amount of pipelining changes so must the tap width used to track valid
data through the pipeline of adders and multipliers. This filter supports
clearing functionality as well if a new data stream is provided at the input.
*/
module custom_FIR (
clk,
reset,
// the "sink" side
sink_data,
sink_valid,
sink_ready,
// the "source" side
source_data,
source_valid,
source_ready,
clear
);
parameter DATA_WIDTH = 16; // input data width (output is wider)
parameter COEF_WIDTH = 8;
parameter NUM_OF_TAPS = 16; // use only an even number of taps of 4, 8, or 16 (for now)
parameter SYMMETRIC = 1; // unused right now, this would either use "NUM_OF_TAPS"/2 multipliers when 1 otherwise "NUM_OF_TAPS" multipliers (un-implemented)
parameter FIFO_DEPTH = 32; // make sure this is at least 32
parameter FIFODEPTH_LOG2 = 5; //log2 of the FIFO_DEPTH
input clk;
input reset;
// the "sink" side
input signed [DATA_WIDTH-1:0] sink_data;
input sink_valid;
output wire sink_ready;
// the "source" side
output wire [(DATA_WIDTH + COEF_WIDTH + 1):0] source_data;
output wire source_valid;
input source_ready;
input clear;
// the internal registers, after taps there are 4 stages of pipelining
reg signed [DATA_WIDTH-1:0] taps [NUM_OF_TAPS-1:0];
reg signed [DATA_WIDTH:0] initial_additions [(NUM_OF_TAPS/2)-1:0]; // addition between two taps, only used in symetric filters
reg signed [DATA_WIDTH+COEF_WIDTH:0] multiplications [(NUM_OF_TAPS/2)-1:0]; // initial_additions * coefficients
reg signed [DATA_WIDTH+COEF_WIDTH+1:0] final_additions [(NUM_OF_TAPS/4)-1:0]; // two multiply results added together and registered
reg signed [DATA_WIDTH+COEF_WIDTH+1:0] final_result; // sum of final_additions
wire signed [DATA_WIDTH+COEF_WIDTH+1:0] final_result_temp;
wire signed [COEF_WIDTH-1:0] coefficients [0: (NUM_OF_TAPS/2) -1];
reg [4:0] tag; // shift register that tracks the valid data moving through the adders and multipliers
// other misc. control signal
wire read_fifo;
wire pipeline_enable;
wire fifo_empty;
wire fifo_half_full;
assign coefficients = '{ `include "coefs.h" };
/**********************************************************************************
TAP PIPELINE
**********************************************************************************/
always @ (posedge clk or posedge reset)
begin
if (reset)
begin
taps[0] <= 0;
end
else if (clear == 1)
begin
taps[0] <= 0;
end
else if (pipeline_enable == 1)
begin
taps[0] <= sink_data;
end
end
genvar tap_counter;
generate
for(tap_counter = 1; tap_counter < NUM_OF_TAPS; tap_counter = tap_counter+1)
begin : the_taps
always @ (posedge clk or posedge reset)
begin
if (reset)
begin
taps[tap_counter] <= 0;
end
else if (clear == 1)
begin
taps[tap_counter] <= 0;
end
else if (pipeline_enable == 1)
begin
taps[tap_counter] <= taps[tap_counter-1];
end
end
end
endgenerate
/**********************************************************************************/
/**********************************************************************************
INITIAL ADDER PIPELINE
**********************************************************************************/
genvar initial_add_counter;
generate
for(initial_add_counter = 0; initial_add_counter < (NUM_OF_TAPS/2); initial_add_counter=initial_add_counter+1)
begin : the_initial_adds
always @ (posedge clk or posedge reset)
begin
if (reset)
begin
initial_additions[initial_add_counter] <= 0;
end
else if (clear == 1)
begin
initial_additions[initial_add_counter] <= 0;
end
else
begin
initial_additions[initial_add_counter] <= taps[initial_add_counter] + taps[NUM_OF_TAPS - 1 - initial_add_counter];
end
end
end
endgenerate
/**********************************************************************************/
/**********************************************************************************
MULTIPLIER PIPELINE
**********************************************************************************/
genvar multiplier_counter;
generate
for(multiplier_counter = 0; multiplier_counter < (NUM_OF_TAPS/2); multiplier_counter=multiplier_counter+1)
begin : the_multipliers
always @ (posedge clk or posedge reset)
begin
if (reset)
begin
multiplications[multiplier_counter] <= 0;
end
else if (clear == 1)
begin
multiplications[multiplier_counter] <= 0;
end
else
begin
multiplications[multiplier_counter] <= initial_additions[multiplier_counter] * coefficients[multiplier_counter];
end
end
end
endgenerate
/**********************************************************************************/
/**********************************************************************************
FINAL ADDER PIPELINE
**********************************************************************************/
genvar final_add_counter;
generate
for(final_add_counter = 0; final_add_counter < (NUM_OF_TAPS/4); final_add_counter=final_add_counter+1)
begin : the_final_adds
always @ (posedge clk or posedge reset)
begin
if (reset)
begin
final_additions[final_add_counter] <= 0;
end
else if (clear == 1)
begin
final_additions[final_add_counter] <= 0;
end
else
begin
final_additions[final_add_counter] <= multiplications[2*final_add_counter] + multiplications[(2*final_add_counter)+1];
end
end
end
endgenerate
/**********************************************************************************/
/**********************************************************************************
FINAL RESULT PIPELINE
**********************************************************************************/
generate
if(NUM_OF_TAPS == 4)
assign final_result_temp = final_additions[0];
else if (NUM_OF_TAPS == 8)
assign final_result_temp = final_additions[0] + final_additions[1];
else if (NUM_OF_TAPS == 16)
assign final_result_temp = final_additions[0] + final_additions[1] + final_additions[2] + final_additions[3];
endgenerate // after 16 taps this should addition should be done with registered stages
always @ (posedge clk or posedge reset)
begin
if (reset)
begin
final_result <= 0;
end
else if (clear == 1)
begin
final_result <= 0;
end
else
begin
final_result <= final_result_temp;
end
end
/**********************************************************************************/
/**********************************************************************************
OUTPUT FIFO AND SYNC LOGIC (used for backpressure purposes)
**********************************************************************************/
assign sink_ready = (fifo_half_full == 0);
assign pipeline_enable = (sink_ready == 1) & (sink_valid == 1);
assign source_valid = (fifo_empty == 0);
assign read_fifo = (source_valid == 1) & (source_ready == 1);
always @ (posedge clk or posedge reset)
begin
if (reset)
begin
tag <= 0;
end
else if (clear == 1)
begin
tag <= 0;
end
else
begin
tag <= {tag[3:0], pipeline_enable};
end
end
scfifo the_output_fifo (
.aclr (reset),
.sclr (clear),
.clock (clk),
.data (final_result),
.almost_full (fifo_half_full),
.empty (fifo_empty),
.q (source_data),
.rdreq (read_fifo),
.wrreq (tag[4]) // tag delay pipeline matches when valid data pops out of "final_result"
);
defparam the_output_fifo.LPM_WIDTH = DATA_WIDTH+COEF_WIDTH+2;
defparam the_output_fifo.LPM_NUMWORDS = FIFO_DEPTH;
defparam the_output_fifo.LPM_WIDTHU = FIFODEPTH_LOG2;
defparam the_output_fifo.ALMOST_FULL_VALUE = FIFO_DEPTH - 2 - 6; // -2 for the FIFO latency, and -6 for the pipelining latency of the FIR operation with room to spare
defparam the_output_fifo.LPM_SHOWAHEAD = "ON";
defparam the_output_fifo.USE_EAB = "ON";
defparam the_output_fifo.ADD_RAM_OUTPUT_REGISTER = "OFF";
defparam the_output_fifo.UNDERFLOW_CHECKING = "OFF";
defparam the_output_fifo.OVERFLOW_CHECKING = "OFF";
/**********************************************************************************/
endmodule