| /* ********************************************************************************* */ |
| /* */ |
| /* 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 |