blob: 3d3543c72a551365231e77b80407634b4d90d2a3 [file] [log] [blame] [edit]
/* ********************************************************************************* */
/* */
/* Main module for biquad filter */
/* */
/* Author: Chuck Cox (chuck100@home.com) */
/* */
/* This filter core uses a wishbone interface for compatibility with other cores: */
/* */
/* Wishbone general description: 16x5 register file */
/* Supported cycles: Slave Read/write, block read/write, RMW */
/* Data port size: 16 bit */
/* Data port granularity: 16 bit */
/* Data port maximum operand size: 16 bit */
/* */
/* Addr register */
/* ---- -------- */
/* 0x0 Filter coefficient a11 */
/* 0x1 Filter coefficient a12 */
/* 0x2 Filter coefficient b10 */
/* 0x3 Filter coefficient b11 */
/* 0x4 Filter coefficient b12 */
/* */
/* Filter coefficients need to be written as 16 bit twos complement fractional */
/* numbers. For example: 0100_0000_0000_0001 = 2^-1 + 2^-15 = .500030517578125 */
/* */
/* The equation for the filter implemented with this core is */
/* y[n] = b10 * x[n] + b11 * x[n-1] + b12 * x[n-2] + a11 * y[n-1] + a12 * y[n-2] */
/* */
/* This biquad filter is parameterized. If a filter with coefficients less than */
/* 16 bits in length is selected via parameters then the most significant bits of */
/* the value written to the filter coefficient register shall be used (ie */
/* coefficients shall be truncated as required by parameter value COEFWIDTH). */
/* */
/* See comments in biquad module for more details on filtering algorthm. */
/* ********************************************************************************* */
`define ACCUM 2
`define COEFWIDTH 8
`define DATAWIDTH 8
/* Must be less than or equal to COEFWIDTH-2 */
module iir1
(
clk_i, /* Wishbone clk */
rst_i, /* Wishbone asynchronous active high reset */
we_i, /* Wishbone write enable */
stb_i, /* Wishbone strobe */
ack_o, /* Wishbone ack */
dat_i, /* Wishbone input data */
dat_o, /* Wishbone output data */
adr_i, /* Wishbone address bus */
dspclk, /* DSP processing clock */
nreset, /* active low asynchronous reset for filter block */
x, /* input data for filter */
valid, /* data valid input */
y /* filter output data */
);
input clk_i;
input rst_i;
input we_i;
input stb_i;
output ack_o;
input [15:0] dat_i;
output [15:0] dat_o;
input [2:0] adr_i;
input dspclk;
input nreset;
input [`DATAWIDTH-1:0] x;
input valid;
output [`DATAWIDTH-1:0] y;
wire [15:0] a11;
wire [15:0] a12;
wire [15:0] b10;
wire [15:0] b11;
wire [15:0] b12;
/* Filter module */
biquad biquadi
(
.clk(dspclk), /* clock */
.nreset(nreset), /* active low reset */
.x(x), /* data input */
.valid(valid), /* input data valid */
.a11(a11[15:16-`COEFWIDTH]), /* filter pole coefficient */
.a12(a12[15:16-`COEFWIDTH]), /* filter pole coefficient */
.b10(b10[15:16-`COEFWIDTH]), /* filter zero coefficient */
.b11(b11[15:16-`COEFWIDTH]), /* filter zero coefficient */
.b12(b12[15:16-`COEFWIDTH]), /* filter zero coefficient */
.yout(y) /* filter output */
);
/* Wishbone interface module */
coefio coefioi
(
.clk_i(clk_i),
.rst_i(rst_i),
.we_i(we_i),
.stb_i(stb_i),
.ack_o(ack_o),
.dat_i(dat_i),
.dat_o(dat_o),
.adr_i(adr_i),
.a11(a11),
.a12(a12),
.b10(b10),
.b11(b11),
.b12(b12)
);
endmodule
/* ********************************************************************************* */
/* Bi-quad IIR filter section */
/* */
/* Author: Chuck Cox (chuck100@home.com) */
/* */
/* This module implements an IIR filter section with 2 poles and */
/* 2 zeros. The filter coefficients are inputs to this module. */
/* Multiple bi-quad filter sections can be connected together to */
/* create higher order filters. The filter uses a signed fractional */
/* 2's complement binary numbering system. For example with 3 bits: */
/* */
/* 000 = 0 001 = 0.25 010 = 0.5 011 = 0.75 */
/* 100 = 0 101 = -.75 110 = -.5 111 = -.25 */
/* */
/* The equation for the filter implemented with this module is */
/* y[n] = b10 * x[n] + b11 * x[n-1] + b12 * x[n-2] + a11 * y[n-1] + a12 * y[n-2] */
/* */
/* Multipliers are implemented as calls to seperate modules to allow easy */
/* conversion to hard or firm macros. Multicycle multipliers can be used */
/* by not making input data valid on every clock. For a 4 clock multiplier */
/* data will need to be valid only once every 4 clocks. */
/* */
/* */
/* ********************************************************************************* */
module biquad
(
clk, /* clock */
nreset, /* active low reset */
x, /* data input */
valid, /* input data valid */
a11, /* filter pole coefficient */
a12, /* filter pole coefficient */
b10, /* filter zero coefficient */
b11, /* filter zero coefficient */
b12, /* filter zero coefficient */
yout /* filter output */
);
// Acumulator width is (`DATAWIDTH + `ACCUM) bits.
input clk;
input nreset;
input [`DATAWIDTH-1:0] x;
input valid;
input [`COEFWIDTH-1:0] a11;
input [`COEFWIDTH-1:0] a12;
input [`COEFWIDTH-1:0] b10;
input [`COEFWIDTH-1:0] b11;
input [`COEFWIDTH-1:0] b12;
output [`DATAWIDTH-1:0] yout;
reg [`DATAWIDTH-1:0] xvalid;
reg [`DATAWIDTH-1:0] xm1;
reg [`DATAWIDTH-1:0] xm2;
reg [`DATAWIDTH-1:0] xm3;
reg [`DATAWIDTH-1:0] xm4;
reg [`DATAWIDTH-1:0] xm5;
reg [`DATAWIDTH+3+`ACCUM:0] sumb10reg;
reg [`DATAWIDTH+3+`ACCUM:0] sumb11reg;
reg [`DATAWIDTH+3+`ACCUM:0] sumb12reg;
reg [`DATAWIDTH+3+`ACCUM:0] suma12reg;
reg [`DATAWIDTH+3:0] y;
reg [`DATAWIDTH-1:0] yout;
wire [`COEFWIDTH-1:0] sa11;
wire [`COEFWIDTH-1:0] sa12;
wire [`COEFWIDTH-1:0] sb10;
wire [`COEFWIDTH-1:0] sb11;
wire [`COEFWIDTH-1:0] sb12;
wire [`DATAWIDTH-2:0] tempsum;
wire [`DATAWIDTH+3+`ACCUM:0] tempsum2;
wire [`DATAWIDTH + `COEFWIDTH - 3:0] mb10out;
wire [`DATAWIDTH+3+`ACCUM:0] sumb10;
wire [`DATAWIDTH + `COEFWIDTH - 3:0] mb11out;
wire [`DATAWIDTH+3+`ACCUM:0] sumb11;
wire [`DATAWIDTH + `COEFWIDTH - 3:0] mb12out;
wire [`DATAWIDTH+3+`ACCUM:0] sumb12;
wire [`DATAWIDTH + `COEFWIDTH + 1:0] ma12out;
wire [`DATAWIDTH+3+`ACCUM:0] suma12;
wire [`DATAWIDTH + `COEFWIDTH + 1:0] ma11out;
wire [`DATAWIDTH+3+`ACCUM:0] suma11;
wire [`DATAWIDTH+2:0] sy;
wire [`DATAWIDTH-1:0] olimit;
/* Two's complement of coefficients */
assign sa11 = a11[`COEFWIDTH-1] ? (-a11) : a11;
assign sa12 = a12[`COEFWIDTH-1] ? (-a12) : a12;
assign sb10 = b10[`COEFWIDTH-1] ? (-b10) : b10;
assign sb11 = b11[`COEFWIDTH-1] ? (-b11) : b11;
assign sb12 = b12[`COEFWIDTH-1] ? (-b12) : b12;
/*
assign sa11 = a11[`COEFWIDTH-1] ? (~a11 + 1) : a11;
assign sa12 = a12[`COEFWIDTH-1] ? (~a12 + 1) : a12;
assign sb10 = b10[`COEFWIDTH-1] ? (~b10 + 1) : b10;
assign sb11 = b11[`COEFWIDTH-1] ? (~b11 + 1) : b11;
assign sb12 = b12[`COEFWIDTH-1] ? (~b12 + 1) : b12;
*/
assign tempsum = -xvalid[`DATAWIDTH-2:0];
//assign tempsum = ~xvalid[`DATAWIDTH-2:0] + 1;
assign tempsum2 = -{4'b0000,mb10out[`COEFWIDTH+`DATAWIDTH-3:`COEFWIDTH-2-`ACCUM]};
//assign tempsum2 = ~{4'b0000,mb10out[`COEFWIDTH+`DATAWIDTH-3:`COEFWIDTH-2-`ACCUM]} + 1;
/* clock data into pipeline. Divide by 8. Convert to sign magnitude. */
always @(posedge clk or negedge nreset)
begin
if ( ~nreset )
begin
xvalid <= 0;
xm1 <= 0;
xm2 <= 0;
xm3 <= 0;
xm4 <= 0;
xm5 <= 0;
end
else
begin
xvalid <= valid ? x : xvalid;
xm1 <= valid ? (xvalid[`DATAWIDTH-1] ? ({xvalid[`DATAWIDTH-1],tempsum}) : {xvalid}) : xm1;
xm2 <= valid ? xm1 : xm2;
xm3 <= valid ? xm2 : xm3;
xm4 <= valid ? xm3 : xm4;
xm5 <= valid ? xm4 : xm5;
end
end
/* Multiply input by filter coefficient b10 */
multb multb10(.a(sb10[`COEFWIDTH-2:0]),.b(xm1[`DATAWIDTH-2:0]),.r(mb10out));
assign sumb10 = (b10[`COEFWIDTH-1] ^ xm1[`DATAWIDTH-1]) ? (tempsum2) : ({4'b0000,mb10out[`COEFWIDTH+`DATAWIDTH-3:`COEFWIDTH-2-`ACCUM]});
/* Multiply input by filter coefficient b11 */
multb multb11(.a(sb11[`COEFWIDTH-2:0]),.b(xm3[`DATAWIDTH-2:0]),.r(mb11out));
/* Divide by two and add or subtract */
assign sumb11 = (b11[`COEFWIDTH-1] ^ xm3[`DATAWIDTH-1]) ? (sumb10reg - {4'b0000,mb11out[`COEFWIDTH+`DATAWIDTH-3:`COEFWIDTH-2-`ACCUM]}) :
(sumb10reg + {4'b0000,mb11out[`COEFWIDTH+`DATAWIDTH-3:`COEFWIDTH-2-`ACCUM]});
/* Multiply input by filter coefficient b12 */
multb multb12(.a(sb12[`COEFWIDTH-2:0]),.b(xm5[`DATAWIDTH-2:0]),.r(mb12out));
assign sumb12 = (b12[`COEFWIDTH-1] ^ xm5[`DATAWIDTH-1]) ? (sumb11reg - {4'b0000,mb12out[`COEFWIDTH+`DATAWIDTH-3:`COEFWIDTH-2-`ACCUM]}) :
(sumb11reg + {4'b0000,mb12out[`COEFWIDTH+`DATAWIDTH-3:`COEFWIDTH-2-`ACCUM]});
/* Twos complement of output for feedback */
//assign sy = y[`DATAWIDTH+3] ? (-y) : y;
assign sy = y[`DATAWIDTH+3] ? (~y + 1) : y;
/* Multiply output by filter coefficient a12 */
multa multa12(.a(sa12[`COEFWIDTH-2:0]),.b(sy[`DATAWIDTH+2:0]),.r(ma12out));
assign suma12 = (a12[`COEFWIDTH-1] ^ y[`DATAWIDTH+3]) ? (sumb12reg - {1'b0,ma12out[`COEFWIDTH+`DATAWIDTH:`COEFWIDTH-2-`ACCUM]}) :
(sumb12reg + {1'b0,ma12out[`COEFWIDTH+`DATAWIDTH:`COEFWIDTH-2-`ACCUM]});
/* Multiply output by filter coefficient a11 */
multa multa11(.a(sa11[`COEFWIDTH-2:0]),.b(sy[`DATAWIDTH+2:0]),.r(ma11out));
assign suma11 = (a11[`COEFWIDTH-1] ^ y[`DATAWIDTH+3]) ? (suma12reg - {1'b0,ma11out[`COEFWIDTH+`DATAWIDTH:`COEFWIDTH-2-`ACCUM]}) :
(suma12reg + {1'b0,ma11out[`COEFWIDTH+`DATAWIDTH:`COEFWIDTH-2-`ACCUM]});
assign olimit = {y[`DATAWIDTH+3],~y[`DATAWIDTH+3],~y[`DATAWIDTH+3],~y[`DATAWIDTH+3],~y[`DATAWIDTH+3],
~y[`DATAWIDTH+3],~y[`DATAWIDTH+3],~y[`DATAWIDTH+3]};
/* State registers */
always @(posedge clk or negedge nreset)
begin
if ( ~nreset )
begin
sumb10reg <= 0;
sumb11reg <= 0;
sumb12reg <= 0;
suma12reg <= 0;
y <= 0;
yout <= 0;
end
else
begin
sumb10reg <= valid ? (sumb10) : (sumb10reg);
sumb11reg <= valid ? (sumb11) : (sumb11reg);
sumb12reg <= valid ? (sumb12) : (sumb12reg);
suma12reg <= valid ? (suma12) : (suma12reg);
y <= valid ? suma11[`DATAWIDTH+3+`ACCUM:`ACCUM] : y;
yout <= valid ? (( (&y[`DATAWIDTH+3:`DATAWIDTH-1]) | (~|y[`DATAWIDTH+3:`DATAWIDTH-1]) ) ?
(y[`DATAWIDTH-1:0]) : (olimit)) : (yout);
end
end
endmodule
/* ********************************************************************************* */
/* Wishbone compatible IO module for read/write of filter coefficients */
/* */
/* Author: Chuck Cox (chuck100@home.com) */
/* */
/* Wishbone data: */
/* General description: 16x5 register file */
/* Supported cycles: Slave Read/write, block read/write, RMW */
/* Data port size: 16 bit */
/* Data port granularity: 16 bit */
/* Data port maximum operand size: 16 bit */
/* */
/* Addr register */
/* 0x0 a11 */
/* 0x1 a12 */
/* 0x2 b10 */
/* 0x3 b11 */
/* 0x4 b12 */
/* */
/* Filter coefficients need to be written as 16 bit twos complement fractional */
/* numbers. For example: 0100_0000_0000_0001 = 2^-1 + 2^-15 = .500030517578125 */
/* */
/* The biquad filter module is parameterized. If a filter with coefficients less */
/* than 16 bits in length is selected then the most significant bits shall be used. */
/* ********************************************************************************* */
module coefio
(
clk_i,
rst_i,
we_i,
stb_i,
ack_o,
dat_i,
dat_o,
adr_i,
a11,
a12,
b10,
b11,
b12
);
input clk_i;
input rst_i;
input we_i;
input stb_i;
output ack_o;
input [15:0] dat_i;
output [15:0] dat_o;
input [2:0] adr_i;
output [15:0] a11;
output [15:0] a12;
output [15:0] b10;
output [15:0] b11;
output [15:0] b12;
reg [15:0] a11;
reg [15:0] a12;
reg [15:0] b10;
reg [15:0] b11;
reg [15:0] b12;
wire ack_o;
wire sel_a11;
wire sel_a12;
wire sel_b10;
wire sel_b11;
wire sel_b12;
assign sel_a11 = (adr_i == 3'b000);
assign sel_a12 = (adr_i == 3'b001);
assign sel_b10 = (adr_i == 3'b010);
assign sel_b11 = (adr_i == 3'b011);
assign sel_b12 = (adr_i == 3'b100);
assign ack_o = stb_i;
always @(posedge clk_i or posedge rst_i)
if ( rst_i )
begin
a11 <= 15'b11111111;
a12 <= 15'b11111;
b10 <= 15'b1111111;
b11 <= 15'b11;
b12 <= 15'b11111111;
/*
a11 <= 15'd0;
a12 <= 15'd0;
b10 <= 15'd0;
b11 <= 15'd0;
b12 <= 15'd0;
*/
end
else
begin
a11 <= (stb_i & we_i & sel_a11) ? (dat_i) : (a11);
a12 <= (stb_i & we_i & sel_a12) ? (dat_i) : (a12);
b10 <= (stb_i & we_i & sel_b10) ? (dat_i) : (b10);
b11 <= (stb_i & we_i & sel_b11) ? (dat_i) : (b11);
b12 <= (stb_i & we_i & sel_b12) ? (dat_i) : (b12);
end
assign dat_o = sel_a11 ? (a11) :
((sel_a12) ? (a12) :
((sel_b10) ? (b10) :
((sel_b11) ? (b11) :
((sel_b12) ? (b12) :
(16'h0000)))));
endmodule
/* ********************************************************************************* */
/* multiplier place holder */
/* */
/* Author: Chuck Cox (chuck100@home.com) */
/* */
/* */
/* */
/* ********************************************************************************* */
module multa
(
// clk,
// nreset,
a, /* data input */
b, /* input data valid */
r /* filter pole coefficient */
);
//input clk;
//input nreset;
input [`COEFWIDTH-2:0] a;
input [`DATAWIDTH+2:0] b;
output [`DATAWIDTH + `COEFWIDTH + 1:0] r;
assign r = a*b;
endmodule
/* ********************************************************************************* */
/* multiplier place holder */
/* */
/* Author: Chuck Cox (chuck100@home.com) */
/* */
/* */
/* */
/* ********************************************************************************* */
module multb
(
a, /* data input */
b, /* input data valid */
r /* filter pole coefficient */
);
input [`COEFWIDTH-2:0] a;
input [`DATAWIDTH-2:0] b;
output [`DATAWIDTH + `COEFWIDTH - 3:0] r;
assign r = a*b;
endmodule