Hello all,
I'm working on a project where I want to implement some FIR bandpass filters in a Spartan 6(XC6SLX9). I've never done this before so I created a proof of concept module to make sure I understand everything. I finished the module and comparing its step response with one generated from Matlab it appears to be working but I have a few questions. Below is the code.
module Bandpass_Filter(
input wire clk,
input wire reset,
input wire[11:0] data_in,
output reg signed[11:0] data_out
);
`include "filter_1_coeff.h" // This file contains the information about the filter.
integer i;
reg shift; // Shifts data in.
reg[9:0] filter_chunk; // Used to time multiplex the 16 DSP slices.
wire signed[47:0] product[0:15]; // Results of multipication.
reg signed[47:0] carry_in; // Carry in, carry out from last calculation.
reg signed[17:0] data_delay[0:num_taps-1]; // Data in.
assign product[0] = data_delay[0+filter_chunk]*coeff[0+filter_chunk] + carry_in; // Multiply the first data and coefficent and add in the carry in.
genvar j;
generate
for(j=1; j<16; j=j+1) begin : product_operate // Create 15 more MAC operations.
assign product[j] = (data_delay[j+filter_chunk]*coeff[j+filter_chunk]) + product[j-1]; // Multiply the data and coefficent and add in the previous carry out.
end
endgenerate
always @(posedge clk or negedge reset) begin
if(!reset) begin
carry_in <= 0;
shift <= 0;
data_out <= 0;
filter_chunk <= 0;
for(i=0; i<num_taps; i=i+1) begin : data_reset
data_delay[i] <= 0;
end
end else begin
carry_in <= product[15]; // Save last value to be the carry in for the next chunk on the next clock cycle.
filter_chunk <= filter_chunk + 16; // Increment to evaluate the next 16 items of data.
shift <= 0;
if(filter_chunk == num_taps-16) begin // When the end is reached shift data and give data output.
data_out <= product[15] >>> coeff_scale;
carry_in <= 0;
filter_chunk <= 0;
shift <= 1;
end
// Shift data when new data arrives.
if(shift) begin
data_delay[0] <= {6'b0, data_in};
for(i=1; i<num_taps; i=i+1) begin : gen_data_shift
data_delay[i] <= data_delay[i-1];
end
end
end
end
endmodule
filter_1_coeff.h
localparam num_taps = 256;
localparam coeff_scale = 16;
localparam signed[17:0] coeff[0:255] = '{5, 0, -6, -14, -20, -23, -23, -18, -9, 3, 16, 27, 35, 37, 32, 22, 7, -8, -22, -32, -35, -32, -24, -12, -1, 6, 9, 6, 0, -7, -11, -8, 2, 20, 42, 63, 77, 76, 59, 24, -23, -75, -121, -150, -155, -133, -84, -17, 56, 120, 164, 178, 160, 116, 57, -4, -54, -81, -83, -64, -33, -6, 5, -8, -47, -103, -159, -195, -194, -142, -40, 100, 253, 387, 468, 472, 388, 222, 0, -238, -447, -584, -621, -551, -387, -164, 71, 270, 395, 429, 375, 261, 129, 25, -16, 21, 124, 256, 361, 382, 274, 25, -343, -766, -1151, -1396, -1408, -1136, -581, 192, 1061, 1866, 2438, 2635, 2377, 1661, 579, -702, -1961, -2966, -3518, -3492, -2863, -1718, -241, 1315, 2680, 3611, 3941, 3611, 2680, 1315, -241, -1718, -2863, -3492, -3518, -2966, -1961, -702, 579, 1661, 2377, 2635, 2438, 1866, 1061, 192, -581, -1136, -1408, -1396, -1151, -766, -343, 25, 274, 382, 361, 256, 124, 21, -16, 25, 129, 261, 375, 429, 395, 270, 71, -164, -387, -551, -621, -584, -447, -238, 0, 222, 388, 472, 468, 387, 253, 100, -40, -142, -194, -195, -159, -103, -47, -8, 5, -6, -33, -64, -83, -81, -54, -4, 57, 116, 160, 178, 164, 120, 56, -17, -84, -133, -155, -150, -121, -75, -23, 24, 59, 76, 77, 63, 42, 20, 2, -8, -11, -7, 0, 6, 9, 6, -1, -12, -24, -32, -35, -32, -22, -8, 7, 22, 32, 37, 35, 27, 16, 3, -9, -18, -23, -23, -20, -14, -6, 0};
First, I've never done DSP with an FPGA so I'm open to any critique about the design. I'm not sure exactly how these are implemented so maybe I'm doing some things in a bad way.
Second, I'm including a header file which defines the filter coefficients but ISE gives me an error for this. It doesn't like the single quote before the coefficient declaration(3rd line, the erorr is just 'Unexpected ' found.'). Modelsim is perfectly fine with this and in fact wont work without it. I believe that's the way you're supposed to define 2 dimensional arrays. What is the deal here? If I remove the quote it will synthesize in ISE but I'm not sure it's being synthesized correctly.
Third, if I remove the quote I mentioned in the second question and synthesize the module. Assuming it is working correctly, it then fails timing. I'm trying to run this module at 100Mhz and I'm getting a max path of 50ns. This seems strange to me and makes me think I'm doing something wrong. I'm daisy chaining the multiplications such they should naturally infer the DSP slices in an efficient manner. I believe that's how these are interned to be configured. So it seems weird that 20Mhz is the fastest they could run. Am I doing something wrong here or is this normal?
Thank you for any help or advice!
It's finally the weekend so I've had some more time to look at this again and I've redesigned as suggested by using only a single multiplier per channel. But I'm still running into the issue that ISE doesn't like the way I've defined my coefficients. Below is an example of how I do it.
localparam num_taps = 1000;
localparam coeff_scale = 16;
localparam signed[17:0] coeff[0:999] = '{0, 3, 5, 8, 9, 10, 10, 9, 6, 3, 0, -4, -8, -11, -13, -14, -13, -11, -8, -4, 0, 4, 9, 12, 14, 15, 14, 12, 9, 5, 0, -4, -7, -10, -12, -12, -11, -9, -7, -4, -1, 2, 4, 6, 6, 6, 5, 4, 2, 1, 0, 0, 0, 1, 2, 3, 4, 4, 4, 3, 1, -2, -5, -8, -11, -13, -14, -14, -12, -8, -3, 3, 9, 15, 20, 23, 24, 22, 19, 13, 5, -3, -11, -19, -25, -28, -29, -27, -22, -15, -7, 2, 11, 19, 24, 27, 28, 25, 20, 14, 6, -1, -8, -13, -17, -18, -18, -15, -12, -8, -3, 0, 3, 4, 3, 2, 0, -2, -3, -4, -3, 0, 4, 9, 14, 19, 23, 24, 23, 19, 11, 2, -10, -21, -32, -40, -45, -46, -42, -33, -20, -4, 13, 30, 44, 55, 61, 61, 54, 43, 26, 7, -13, -31, -47, -58, -63, -62, -55, -43, -27, -9, 9, 25, 38, 46, 48, 46, 39, 29, 18, 6, -4, -12, -17, -18, -16, -13, -8, -3, 0, 1, -1, -5, -12, -20, -27, -33, -35, -32, -25, -13, 4, 23, 42, 59, 73, 80, 79, 69, 51, 26, -3, -35, -65, -90, -108, -115, -112, -96, -71, -38, 0, 39, 74, 102, 121, 128, 122, 104, 76, 42, 4, -33, -65, -89, -104, -107, -100, -83, -60, -33, -6, 19, 39, 51, 56, 54, 46, 34, 21, 10, 2, -2, 0, 6, 16, 26, 34, 38, 36, 26, 9, -14, -42, -70, -95, -114, -122, -117, -99, -68, -25, 24, 76, 124, 163, 188, 195, 183, 152, 103, 42, -25, -93, -152, -199, -226, -231, -214, -175, -120, -53, 19, 87, 146, 188, 211, 212, 193, 156, 106, 49, -9, -60, -101, -127, -137, -132, -114, -87, -55, -24, 1, 19, 26, 24, 14, 0, -14, -25, -28, -20, -1, 27, 63, 100, 134, 158, 167, 158, 128, 78, 12, -65, -144, -216, -272, -305, -309, -280, -221, -135, -30, 84, 196, 292, 363, 399, 397, 356, 278, 172, 48, -82, -203, -304, -373, -406, -398, -351, -272, -169, -55, 59, 160, 239, 289, 305, 290, 248, 186, 113, 39, -26, -75, -105, -113, -103, -79, -49, -20, 0, 6, -6, -34, -75, -123, -169, -203, -216, -201, -155, -79, 23, 141, 262, 371, 454, 497, 492, 432, 321, 166, -21, -219, -409, -570, -682, -731, -708, -613, -453, -241, 0, 247, 475, 659, 781, 826, 789, 676, 498, 273, 26, -217, -431, -595, -693, -719, -673, -564, -408, -225, -38, 132, 267, 355, 391, 377, 323, 242, 152, 70, 12, -13, 0, 47, 116, 193, 258, 291, 277, 205, 72, -113, -335, -568, -781, -943, -1023, -997, -852, -590, -224, 215, 686, 1140, 1523, 1785, 1886, 1799, 1516, 1051, 439, -267, -999, -1682, -2241, -2609, -2737, -2596, -2185, -1533, -694, 256, 1225, 2115, 2833, 3298, 3454, 3275, 2766, 1969, 954, -183, -1332, -2377, -3213, -3752, -3934, -3735, -3170, -2288, -1173, 66, 1310, 2435, 3329, 3904, 4102, 3904, 3329, 2435, 1310, 66, -1173, -2288, -3170, -3735, -3934, -3752, -3213, -2377, -1332, -183, 954, 1969, 2766, 3275, 3454, 3298, 2833, 2115, 1225, 256, -694, -1533, -2185, -2596, -2737, -2609, -2241, -1682, -999, -267, 439, 1051, 1516, 1799, 1886, 1785, 1523, 1140, 686, 215, -224, -590, -852, -997, -1023, -943, -781, -568, -335, -113, 72, 205, 277, 291, 258, 193, 116, 47, 0, -13, 12, 70, 152, 242, 323, 377, 391, 355, 267, 132, -38, -225, -408, -564, -673, -719, -693, -595, -431, -217, 26, 273, 498, 676, 789, 826, 781, 659, 475, 247, 0, -241, -453, -613, -708, -731, -682, -570, -409, -219, -21, 166, 321, 432, 492, 497, 454, 371, 262, 141, 23, -79, -155, -201, -216, -203, -169, -123, -75, -34, -6, 6, 0, -20, -49, -79, -103, -113, -105, -75, -26, 39, 113, 186, 248, 290, 305, 289, 239, 160, 59, -55, -169, -272, -351, -398, -406, -373, -304, -203, -82, 48, 172, 278, 356, 397, 399, 363, 292, 196, 84, -30, -135, -221, -280, -309, -305, -272, -216, -144, -65, 12, 78, 128, 158, 167, 158, 134, 100, 63, 27, -1, -20, -28, -25, -14, 0, 14, 24, 26, 19, 1, -24, -55, -87, -114, -132, -137, -127, -101, -60, -9, 49, 106, 156, 193, 212, 211, 188, 146, 87, 19, -53, -120, -175, -214, -231, -226, -199, -152, -93, -25, 42, 103, 152, 183, 195, 188, 163, 124, 76, 24, -25, -68, -99, -117, -122, -114, -95, -70, -42, -14, 9, 26, 36, 38, 34, 26, 16, 6, 0, -2, 2, 10, 21, 34, 46, 54, 56, 51, 39, 19, -6, -33, -60, -83, -100, -107, -104, -89, -65, -33, 4, 42, 76, 104, 122, 128, 121, 102, 74, 39, 0, -38, -71, -96, -112, -115, -108, -90, -65, -35, -3, 26, 51, 69, 79, 80, 73, 59, 42, 23, 4, -13, -25, -32, -35, -33, -27, -20, -12, -5, -1, 1, 0, -3, -8, -13, -16, -18, -17, -12, -4, 6, 18, 29, 39, 46, 48, 46, 38, 25, 9, -9, -27, -43, -55, -62, -63, -58, -47, -31, -13, 7, 26, 43, 54, 61, 61, 55, 44, 30, 13, -4, -20, -33, -42, -46, -45, -40, -32, -21, -10, 2, 11, 19, 23, 24, 23, 19, 14, 9, 4, 0, -3, -4, -3, -2, 0, 2, 3, 4, 3, 0, -3, -8, -12, -15, -18, -18, -17, -13, -8, -1, 6, 14, 20, 25, 28, 27, 24, 19, 11, 2, -7, -15, -22, -27, -29, -28, -25, -19, -11, -3, 5, 13, 19, 22, 24, 23, 20, 15, 9, 3, -3, -8, -12, -14, -14, -13, -11, -8, -5, -2, 1, 3, 4, 4, 4, 3, 2, 1, 0, 0, 0, 1, 2, 4, 5, 6, 6, 6, 4, 2, -1, -4, -7, -9, -11, -12, -12, -10, -7, -4, 0, 5, 9, 12, 14, 15, 14, 12, 9, 4, 0, -4, -8, -11, -13, -14, -13, -11, -8, -4, 0, 3, 6, 9, 10, 10, 9, 8, 5, 3};
I get the error:
ERROR:HDLCompiler:806 - "filter_coeff_15.h" Line 3: Syntax error near "'".
So it doesn't like the single quote before the "{". But my understanding is that this is how this is defined. If I remove the single quote then it will compile but I get 12000 warnings and the design is too large for the FPGA. I think it's treating the coefficient as like 18000 bit register or something. What am I doing wrong here?
In case it's useful below is my current code. I haven't tested it yet because of the above problem so there might be errors.
`timescale 1ns / 1ps
module Bandpass_Filter(
input wire clk,
input wire reset,
input wire[11:0] data_in,
output reg signed[11:0] data_out
);
`include "filter_coeff_15.h" // This file contains the information about the filter.
integer i;
reg shift; // Shifts data in.
reg[15:0] data_index; // Index of the delay data. This should be parameteized later.
reg signed[17:0] data_delay[0:num_taps-1]; // Data in.
wire signed[47:0] product; // Results of multipication.
reg signed[47:0] carry_in; // Carry in, carry out from last calculation.
always @(posedge clk or negedge reset) begin
if(!reset) begin
shift <= 0;
carry_in <= 0;
data_out <= 0;
for(i=0; i<num_taps; i=i+1) begin : data_reset
data_delay[i] <= 0;
end
end else begin
if(!shift) begin // Operate on the data when not shifting.
if(data_index < num_taps) begin
data_index <= data_index + 1;
carry_in <= data_delay[data_index]*coeff[data_index] + carry_in; // Later buffer the coefficent value rather than accessing directly.
end else begin
shift <= 1; // Delete later
end
end else begin // Shift data when new data arrives.
data_index <= 0;
carry_in <= 0;
shift <= 0; // Delete later.
data_out <= carry_in >>> coeff_scale; // Scale the data and output it.
data_delay[0] <= {6'b0, data_in}; // Take in the new data;
for(i=1; i<num_taps; i=i+1) begin : gen_data_shift // Shift all the data.
data_delay[i] <= data_delay[i-1];
end
end
end
end
endmodule
I've been trying my hand a Verilog, and learnt something...
localparam signed[17:0] coeff[0:255] = {
5, 0, -6, -14, -20, -23, -23, -18, -9, 3, 16, 27, 35, 37, 32,
22, 7, -8, -22, -32, -35, -32, -24, -12, -1, 6, 9, 6, 0, -7, -11, -8, 2, 20, 42, 63, 77, 76, 59,
24, -23, -75, -121, -150, -155, -133, -84, -17, 56, 120, 164, 178, 160, 116, 57, -4, -54, -81, -83,
-64, -33, -6, 5, -8, -47, -103, -159, -195, -194, -142, -40, 100, 253, 387, 468, 472, 388, 222, 0,
-238, -447, -584, -621, -551, -387, -164, 71, 270, 395, 429, 375, 261, 129, 25, -16, 21, 124, 256,
361, 382, 274, 25, -343, -766, -1151, -1396, -1408, -1136, -581, 192, 1061, 1866, 2438, 2635, 2377,
1661, 579, -702, -1961, -2966, -3518, -3492, -2863, -1718, -241, 1315, 2680, 3611, 3941, 3611, 2680,
1315, -241, -1718, -2863, -3492, -3518, -2966, -1961, -702, 579, 1661, 2377, 2635, 2438, 1866, 1061,
192, -581, -1136, -1408, -1396, -1151, -766, -343, 25, 274, 382, 361, 256, 124, 21, -16, 25, 129, 261,
375, 429, 395, 270, 71, -164, -387, -551, -621, -584, -447, -238, 0, 222, 388, 472, 468, 387, 253, 100,
-40, -142, -194, -195, -159, -103, -47, -8, 5, -6, -33, -64, -83, -81, -54, -4, 57, 116, 160, 178,
164, 120, 56, -17, -84, -133, -155, -150, -121, -75, -23, 24, 59, 76, 77, 63, 42, 20, 2, -8, -11, -7,
0, 6, 9, 6, -1, -12, -24, -32, -35, -32, -22, -8, 7, 22, 32, 37, 35, 27, 16, 3, -9, -18, -23, -23, -20, -14, -6, 0};
Gives the following error:
WARNING:HDLCompiler:413 - "C:\Users\Hamster\Desktop\Projects\filter_test\bandpass.v" Line 11: Result of 8163-bit expression is truncated to fit in 4608-bit target.
This makes me think that it is attempting to concatenate 255 32-bit binary numbers together, rather than 255 18-bit numbers