差别
这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
fpga滤波器实现 [2020/07/23 16:24] gongyu |
— (当前版本) | ||
---|---|---|---|
行 1: | 行 1: | ||
- | ### 用FPGA实现各种数字滤波器 | ||
- | \\ | ||
- | |||
- | #### FPGA滤波器实施概述 | ||
- | 本篇部分内容来自网站[[https://www.nicholasmikstas.com/fpga-filter-implementation|FPGA滤波器实现]]的一些项目,源于一位在校学生的学习和设计- 了解并在FPGA上实现几种类型的数字滤波器器,设计的所有滤波器均为15阶滤波器,并使用16位定点数学运算,该学生有一篇PPT可供参考:\\ | ||
- | |||
- | [[https://www.eetree.cn/wiki/_media/filter_implementation_on_a_fpga_board_xueyan_lu_06152017.pdf|FPGA滤波器实现]]\\ | ||
- | |||
- | 研究项目期间创建的Verilog源文件如下。\\ | ||
- | \\ | ||
- | |||
- | #### FIR滤波器 | ||
- | FIR滤波器是四个滤波器中最简单,最快的。它利用了预加器的对称性。而且,使用加法器树来最小化组合路径延迟。\\ | ||
- | {{ ::fir_filter.png |}} | ||
- | |||
- | ##### FIR_Filter.v | ||
- | <code verilog> | ||
- | |||
- | `define FILT_LENGTH 16 | ||
- | |||
- | module FIR_Filter( | ||
- | input clk, | ||
- | input en, | ||
- | input [15:0]din, | ||
- | output [15:0]dout | ||
- | ); | ||
- | |||
- | reg signed [15:0]coeff[`FILT_LENGTH/2-1:0]; //Filter coefficients. | ||
- | reg signed [15:0]delay_line[`FILT_LENGTH-1:0]; //Input delay line. | ||
- | wire [31:0]accum; //Accumulator for output filter calculation. | ||
- | integer i; //Initialization integer. | ||
- | genvar c; //Delay line generation variable. | ||
- | |||
- | reg signed [16:0]preadd_regs[7:0]; //Save calc after preadd. | ||
- | reg signed [31:0]mult_regs[7:0]; //Save calc after multiplication. | ||
- | reg signed [31:0]tree1_regs[3:0]; //Save calc after first layer of adder tree. | ||
- | reg signed [31:0]tree2_regs[1:0]; //Save calc after first layer of adder tree. | ||
- | reg signed [31:0]treeout_reg; //Save calc after complete. | ||
- | |||
- | //assign dout = treeout_reg[31:16]; | ||
- | | ||
- | //Calculate value in the accumulator. | ||
- | assign accum = (delay_line[0] + delay_line[15]) * coeff[0] + | ||
- | (delay_line[1] + delay_line[14]) * coeff[1] + | ||
- | (delay_line[2] + delay_line[13]) * coeff[2] + | ||
- | (delay_line[3] + delay_line[12]) * coeff[3] + | ||
- | (delay_line[4] + delay_line[11]) * coeff[4] + | ||
- | (delay_line[5] + delay_line[10]) * coeff[5] + | ||
- | (delay_line[6] + delay_line[9]) * coeff[6] + | ||
- | (delay_line[7] + delay_line[8]) * coeff[7]; | ||
- | |||
- | //Assign upper 16-bits to output. | ||
- | assign dout = accum[31:16]; | ||
- | | ||
- | initial begin | ||
- | //Load the filter coefficients. | ||
- | coeff[0] = 16'd2320; | ||
- | coeff[1] = 16'd4143; | ||
- | coeff[2] = 16'd4592; | ||
- | coeff[3] = 16'd7278; | ||
- | coeff[4] = 16'd8423; | ||
- | coeff[5] = 16'd10389; | ||
- | coeff[6] = 16'd11269; | ||
- | coeff[7] = 16'd12000; | ||
- | |||
- | //Initialize delay line. | ||
- | for(i = 0; i < `FILT_LENGTH; i = i+1'b1) begin | ||
- | delay_line[i] = 16'd0; | ||
- | end | ||
- | | ||
- | //Initialize the preadder regs. | ||
- | for(i = 0; i < 8; i = i+1'b1) begin | ||
- | preadd_regs[i] = 17'd0; | ||
- | end | ||
- | | ||
- | //Initialize the multiplier regs. | ||
- | for(i = 0; i < 8; i = i+1'b1) begin | ||
- | mult_regs[i] = 32'd0; | ||
- | end | ||
- | | ||
- | //Initialize the first layer of the adder tree regs. | ||
- | for(i = 0; i < 4; i = i+1'b1) begin | ||
- | tree1_regs[i] = 32'd0; | ||
- | end | ||
- | | ||
- | //Initialize the second layer of the adder tree regs. | ||
- | for(i = 0; i < 2; i = i+1'b1) begin | ||
- | tree2_regs[i] = 32'd0; | ||
- | end | ||
- | | ||
- | //Initialize the adder tree output reg. | ||
- | treeout_reg = 32'd0; | ||
- | end | ||
- | | ||
- | //Advance the data through the delay line every clock cycle. | ||
- | generate | ||
- | for (c = `FILT_LENGTH-1; c > 0; c = c - 1) begin: inc_delay | ||
- | always @(posedge clk) begin | ||
- | if(en) delay_line[c] <= delay_line[c-1]; | ||
- | end | ||
- | end | ||
- | endgenerate | ||
- | | ||
- | //Update with input data. | ||
- | always @(posedge clk) begin | ||
- | if(en) delay_line[0] <= din; | ||
- | end | ||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | ##### filter_top.v | ||
- | <code verilog> | ||
- | |||
- | module filter_top( | ||
- | input clk, | ||
- | input [7:0]sw, | ||
- | output [7:0]JA | ||
- | ); | ||
- | | ||
- | wire [15:0]tout; //The output of the tone lookup table. | ||
- | wire [15:0]fout; //The output of the FIR filter. | ||
- | wire [15:0]mout; //Selected output. | ||
- | wire en; //Clock enble. | ||
- | wire clk_out; //264MHz System clock. | ||
- | | ||
- | assign en = 1'b1; | ||
- | | ||
- | clk_wiz_0 cw (.clk_in1(clk), .clk_out1(clk_out)); | ||
- | //clk_en ce(.clk(clk_out), .en(en)); | ||
- | ToneGen tg(.clk(clk_out), .en(en), .dout(tout)); | ||
- | FIR_Filter ff(.clk(clk_out), .en(en), .din(tout), .dout(fout)); | ||
- | | ||
- | //Choose filtered or unfiltered output based on sw0. | ||
- | assign mout = sw[0] ? fout : tout; | ||
- | | ||
- | //Take only the upper 8 bits and make it unsigned. | ||
- | //assign JA = mout[15:8] + 8'd128; | ||
- | assign {JA[3:0], JA[7:4]} = mout[15:8] + 8'd128; | ||
- | | ||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | ##### ToneGen.v | ||
- | <code verilog> | ||
- | |||
- | `timescale 1ns/1ps | ||
- | |||
- | module ToneGen( | ||
- | input clk, | ||
- | input en, | ||
- | output [15:0]dout | ||
- | ); | ||
- | |||
- | //Tone generation data. At a 44KHz sampling rate, the lookup table | ||
- | //generates a 440Hz and 4.4KHz tone mixed together. | ||
- | reg [15:0]tonetbl[99:0]; | ||
- | | ||
- | //Pointer into the tone table. | ||
- | reg [6:0]toneptr = 7'h00; | ||
- | | ||
- | initial begin | ||
- | tonetbl[0] = 10970; | ||
- | tonetbl[1] = 18151; | ||
- | tonetbl[2] = 19197; | ||
- | tonetbl[3] = 14105; | ||
- | tonetbl[4] = 5211; | ||
- | tonetbl[5] = -3704; | ||
- | tonetbl[6] = -8858; | ||
- | tonetbl[7] = -7914; | ||
- | tonetbl[8] = -876; | ||
- | tonetbl[9] = 9912; | ||
- | tonetbl[10] = 20660; | ||
- | tonetbl[11] = 27581; | ||
- | tonetbl[12] = 28330; | ||
- | tonetbl[13] = 22905; | ||
- | tonetbl[14] = 13642; | ||
- | tonetbl[15] = 4326; | ||
- | tonetbl[16] = -1260; | ||
- | tonetbl[17] = -780; | ||
- | tonetbl[18] = 5767; | ||
- | tonetbl[19] = 16037; | ||
- | tonetbl[20] = 26244; | ||
- | tonetbl[21] = 32601; | ||
- | tonetbl[22] = 32767; | ||
- | tonetbl[23] = 26741; | ||
- | tonetbl[24] = 16863; | ||
- | tonetbl[25] = 6918; | ||
- | tonetbl[26] = 692; | ||
- | tonetbl[27] = 527; | ||
- | tonetbl[28] = 6421; | ||
- | tonetbl[29] = 16037; | ||
- | tonetbl[30] = 25590; | ||
- | tonetbl[31] = 31295; | ||
- | tonetbl[32] = 30814; | ||
- | tonetbl[33] = 24149; | ||
- | tonetbl[34] = 13642; | ||
- | tonetbl[35] = 3081; | ||
- | tonetbl[36] = -3745; | ||
- | tonetbl[37] = -4494; | ||
- | tonetbl[38] = 837; | ||
- | tonetbl[39] = 9912; | ||
- | tonetbl[40] = 18947; | ||
- | tonetbl[41] = 24161; | ||
- | tonetbl[42] = 23217; | ||
- | tonetbl[43] = 16119; | ||
- | tonetbl[44] = 5211; | ||
- | tonetbl[45] = -5718; | ||
- | tonetbl[46] = -12878; | ||
- | tonetbl[47] = -13924; | ||
- | tonetbl[48] = -8853; | ||
- | tonetbl[49] = 0; | ||
- | tonetbl[50] = 8853; | ||
- | tonetbl[51] = 13924; | ||
- | tonetbl[52] = 12878; | ||
- | tonetbl[53] = 5718; | ||
- | tonetbl[54] = -5211; | ||
- | tonetbl[55] = -16119; | ||
- | tonetbl[56] = -23217; | ||
- | tonetbl[57] = -24161; | ||
- | tonetbl[58] = -18947; | ||
- | tonetbl[59] = -9912; | ||
- | tonetbl[60] = -837; | ||
- | tonetbl[61] = 4494; | ||
- | tonetbl[62] = 3745; | ||
- | tonetbl[63] = -3081; | ||
- | tonetbl[64] = -13642; | ||
- | tonetbl[65] = -24149; | ||
- | tonetbl[66] = -30814; | ||
- | tonetbl[67] = -31295; | ||
- | tonetbl[68] = -25590; | ||
- | tonetbl[69] = -16037; | ||
- | tonetbl[70] = -6421; | ||
- | tonetbl[71] = -527; | ||
- | tonetbl[72] = -692; | ||
- | tonetbl[73] = -6918; | ||
- | tonetbl[74] = -16863; | ||
- | tonetbl[75] = -26741; | ||
- | tonetbl[76] = -32767; | ||
- | tonetbl[77] = -32601; | ||
- | tonetbl[78] = -26244; | ||
- | tonetbl[79] = -16037; | ||
- | tonetbl[80] = -5767; | ||
- | tonetbl[81] = 780; | ||
- | tonetbl[82] = 1260; | ||
- | tonetbl[83] = -4326; | ||
- | tonetbl[84] = -13642; | ||
- | tonetbl[85] = -22905; | ||
- | tonetbl[86] = -28330; | ||
- | tonetbl[87] = -27581; | ||
- | tonetbl[88] = -20660; | ||
- | tonetbl[89] = -9912; | ||
- | tonetbl[90] = 876; | ||
- | tonetbl[91] = 7914; | ||
- | tonetbl[92] = 8858; | ||
- | tonetbl[93] = 3704; | ||
- | tonetbl[94] = -5211; | ||
- | tonetbl[95] = -14105; | ||
- | tonetbl[96] = -19197; | ||
- | tonetbl[97] = -18151; | ||
- | tonetbl[98] = -10970; | ||
- | tonetbl[99] = 0; | ||
- | end | ||
- | |||
- | //Assign the output to the value in the lookup table | ||
- | //pointed to by toneptr. | ||
- | assign dout = tonetbl[toneptr]; | ||
- | |||
- | //Increment through the tone lookup table and wrap back | ||
- | //to zero when at the end. | ||
- | always @(posedge clk) begin | ||
- | if(en) begin | ||
- | if(toneptr == 7'd99) begin | ||
- | toneptr <= 7'd0; | ||
- | end | ||
- | else begin | ||
- | toneptr <= toneptr + 1'b1; | ||
- | end | ||
- | end | ||
- | end | ||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | |||
- | ##### clk_en.v | ||
- | <code verilog> | ||
- | |||
- | module clk_en( | ||
- | input clk, | ||
- | output reg en = 1'b0 | ||
- | ); | ||
- | |||
- | reg [15:0]en_counter = 16'h0; | ||
- | | ||
- | always @(posedge clk) begin | ||
- | if(en_counter == 16'd5999) begin | ||
- | en_counter <= 16'h0; | ||
- | en <= 1'b1; | ||
- | end | ||
- | else begin | ||
- | en_counter <= en_counter + 1'b1; | ||
- | en <= 1'b0; | ||
- | end | ||
- | end | ||
- | |||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | ##### TB_ToneGen.v | ||
- | <code verilog> | ||
- | |||
- | module TB_ToneGen; | ||
- | |||
- | reg clk = 1'b0; | ||
- | reg sw0 = 1'b1; | ||
- | wire [7:0]JA; | ||
- | | ||
- | wire en; | ||
- | //wire [15:0]cout; | ||
- | | ||
- | filter_top uut(.clk(clk), .sw({15'h00,sw0}), .JA({JA[3:0], JA[7:4]})); | ||
- | | ||
- | assign en = uut.en; | ||
- | //assign cout = uut.ce.en_counter; | ||
- | | ||
- | //initial begin | ||
- | // #600000 sw0 = 1'b1; | ||
- | //end | ||
- | | ||
- | //100MHz clock | ||
- | always #5 clk = ~clk; | ||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | \\ | ||
- | #### LMS自适应滤波器 | ||
- | LMS自适应滤波器在单个时钟周期内完成其输出计算和权重更新。由于其单周期运行,因此存在大量的组合延迟。该滤波器只能以FIR滤波器速度的一小部分运行。\\ | ||
- | {{ ::lms_adaptive_filter.png |}} | ||
- | |||
- | ##### LMS_Adapt.v | ||
- | <code verilog> | ||
- | |||
- | `define ADAPT_FILT_LENGTH 16 | ||
- | module LMS_Adapt( | ||
- | input clk, | ||
- | input en, | ||
- | input [15:0]din, | ||
- | input signed [15:0]desired, | ||
- | output signed [15:0]dout, | ||
- | output signed [15:0]err | ||
- | ); | ||
- | |||
- | parameter MU = 16'd32767; | ||
- | | ||
- | reg signed [15:0]mu = MU; | ||
- | reg signed [15:0]coeff[`ADAPT_FILT_LENGTH-1:0]; //Filter coefficients. | ||
- | reg signed [15:0]delay_line[`ADAPT_FILT_LENGTH-1:0]; //Input delay line. | ||
- | wire signed [31:0]accum; //Accumulator for output filter calculation. | ||
- | wire signed [31:0]stepped; //Error after step sized applied. | ||
- | integer i; //Initialization integer. | ||
- | genvar c; //Delay line generation variable. | ||
- | | ||
- | //Calculate the error and multiply it by the step size. | ||
- | assign err = desired - dout; | ||
- | //assign stepped = err * mu; | ||
- | assign stepped = err << 15; | ||
- | | ||
- | //Calculate value in the accumulator. | ||
- | assign accum = delay_line[0]*coeff[0] + | ||
- | delay_line[1]*coeff[1] + | ||
- | delay_line[2]*coeff[2] + | ||
- | delay_line[3]*coeff[3] + | ||
- | delay_line[4]*coeff[4] + | ||
- | delay_line[5]*coeff[5] + | ||
- | delay_line[6]*coeff[6] + | ||
- | delay_line[7]*coeff[7] + | ||
- | delay_line[8]*coeff[8] + | ||
- | delay_line[9]*coeff[9] + | ||
- | delay_line[10]*coeff[10] + | ||
- | delay_line[11]*coeff[11] + | ||
- | delay_line[12]*coeff[12] + | ||
- | delay_line[13]*coeff[13] + | ||
- | delay_line[14]*coeff[14] + | ||
- | delay_line[15]*coeff[15]; | ||
- | |||
- | //Assign upper 16-bits to output. | ||
- | assign dout = accum[31:16]; | ||
- | |||
- | initial begin | ||
- | //Load the filter coefficients. | ||
- | coeff[0] = 20'd0; | ||
- | coeff[1] = 20'd0; | ||
- | coeff[2] = 20'd0; | ||
- | coeff[3] = 20'd0; | ||
- | coeff[4] = 20'd0; | ||
- | coeff[5] = 20'd0; | ||
- | coeff[6] = 20'd0; | ||
- | coeff[7] = 20'd0; | ||
- | coeff[8] = 20'd0; | ||
- | coeff[9] = 20'd0; | ||
- | coeff[10] = 20'd0; | ||
- | coeff[11] = 20'd0; | ||
- | coeff[12] = 20'd0; | ||
- | coeff[13] = 20'd0; | ||
- | coeff[14] = 20'd0; | ||
- | coeff[15] = 20'd0; | ||
- | |||
- | //Initialize delay line. | ||
- | for(i = 0; i < `ADAPT_FILT_LENGTH; i = i+1'b1) begin | ||
- | delay_line[i] = 16'd0; | ||
- | end | ||
- | end | ||
- | | ||
- | //Advance the data through the delay line every clock cycle. | ||
- | generate | ||
- | for (c = `ADAPT_FILT_LENGTH-1; c > 0; c = c - 1) begin: inc_delay | ||
- | always @(posedge clk) begin | ||
- | if(en) delay_line[c] <= delay_line[c-1]; | ||
- | end | ||
- | end | ||
- | endgenerate | ||
- | | ||
- | //Update with input data. | ||
- | always @(posedge clk) begin | ||
- | if(en) delay_line[0] <= din; | ||
- | end | ||
- | | ||
- | wire signed [31:0]num2[`ADAPT_FILT_LENGTH-1:0]; | ||
- | wire signed [15:0]n1[`ADAPT_FILT_LENGTH-1:0]; | ||
- | wire signed [15:0]n2[`ADAPT_FILT_LENGTH-1:0]; | ||
- | | ||
- | //Update the coefficients with the LMS algorithm. | ||
- | generate | ||
- | for (c = `ADAPT_FILT_LENGTH; c > 0; c = c - 1) begin: adapt_update | ||
- | assign n1[c-1] = stepped[31:16]; | ||
- | | ||
- | assign num2[c-1] = n1[c-1]*delay_line[c-1]; | ||
- | assign n2[c-1] = num2[c-1][31:16]; | ||
- | | ||
- | always @(posedge clk) begin | ||
- | if(en) coeff[c-1] <= coeff[c-1] + n2[c-1]; | ||
- | end | ||
- | end | ||
- | endgenerate | ||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | ##### filter_top.v | ||
- | <code verilog> | ||
- | |||
- | module filter_top( | ||
- | input clk, | ||
- | input [7:0]sw, | ||
- | output [7:0]JA | ||
- | ); | ||
- | | ||
- | wire signed [15:0]tout; //Output of the tone lookup table. | ||
- | wire [15:0]fout; //Output of the FIR filter. | ||
- | wire [15:0]aout; //Output of the adaptive filter. | ||
- | wire [15:0]err; //Adaptive filter error. | ||
- | wire [15:0]lfsr_out; //16-bit Random noise variable. | ||
- | wire en; //Clock enble. | ||
- | wire [9:0]rnd; //10-bit noise. | ||
- | wire signed [15:0]tone_and_noise; //Combination of tone and noise. | ||
- | wire signed [15:0]delay_out; //Output of the delay line. | ||
- | wire [15:0]mout; //Selected desired output. | ||
- | wire clk19_8MHz; //19.8MHz system clock. | ||
- | |||
- | assign rnd = lfsr_out[15:6]; | ||
- | assign tone_and_noise = tout + rnd; | ||
- | //assign en = 1'b1; | ||
- | | ||
- | clk_wiz_0 cw(.clk_in1(clk), .clk_out1(clk19_8MHz), .reset(1'b0)); | ||
- | ToneGen tg(.clk(clk19_8MHz), .en(en), .dout(tout)); | ||
- | FIR_Filter ff(.clk(clk19_8MHz), .en(en), .din(tone_and_noise), .dout(fout)); | ||
- | LMS_Adapt af(.clk(clk19_8MHz), .en(en), .din(tone_and_noise), .desired(mout), .dout(aout), .err(err)); | ||
- | lfsr sr(.clk(clk19_8MHz), .en(en), .lfsr_out(lfsr_out)); | ||
- | clk_en ce(.clk(clk19_8MHz), .en(en)); | ||
- | | ||
- | //Choose filtered or unfiltered output based on sw0. | ||
- | assign mout = sw[0] ? fout : tone_and_noise;//delay_out; | ||
- | | ||
- | //Take only the upper 8 bits and make it unsigned. | ||
- | assign {JA[3:0], JA[7:4]} = aout[15:8] + 8'd128; | ||
- | //assign JA[7:0] = aout[15:8] + 8'd128; | ||
- | | ||
- | //assign {JA[3:0], JA[7:4]} = sw[7:0]; | ||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | ##### ToneGen.v | ||
- | <code verilog> | ||
- | |||
- | `timescale 1ns/1ps | ||
- | |||
- | module ToneGen( | ||
- | input clk, | ||
- | input en, | ||
- | output [15:0]dout | ||
- | ); | ||
- | |||
- | //Tone generation data. At a 44KHz sampling rate, the lookup table | ||
- | //generates a 440Hz and 4.4KHz tone mixed together. | ||
- | reg [15:0]tonetbl[99:0]; | ||
- | | ||
- | //Pointer into the tone table. | ||
- | reg [6:0]toneptr = 7'h00; | ||
- | | ||
- | initial begin | ||
- | tonetbl[0] = 10970; | ||
- | tonetbl[1] = 18151; | ||
- | tonetbl[2] = 19197; | ||
- | tonetbl[3] = 14105; | ||
- | tonetbl[4] = 5211; | ||
- | tonetbl[5] = -3704; | ||
- | tonetbl[6] = -8858; | ||
- | tonetbl[7] = -7914; | ||
- | tonetbl[8] = -876; | ||
- | tonetbl[9] = 9912; | ||
- | tonetbl[10] = 20660; | ||
- | tonetbl[11] = 27581; | ||
- | tonetbl[12] = 28330; | ||
- | tonetbl[13] = 22905; | ||
- | tonetbl[14] = 13642; | ||
- | tonetbl[15] = 4326; | ||
- | tonetbl[16] = -1260; | ||
- | tonetbl[17] = -780; | ||
- | tonetbl[18] = 5767; | ||
- | tonetbl[19] = 16037; | ||
- | tonetbl[20] = 26244; | ||
- | tonetbl[21] = 32601; | ||
- | tonetbl[22] = 32767; | ||
- | tonetbl[23] = 26741; | ||
- | tonetbl[24] = 16863; | ||
- | tonetbl[25] = 6918; | ||
- | tonetbl[26] = 692; | ||
- | tonetbl[27] = 527; | ||
- | tonetbl[28] = 6421; | ||
- | tonetbl[29] = 16037; | ||
- | tonetbl[30] = 25590; | ||
- | tonetbl[31] = 31295; | ||
- | tonetbl[32] = 30814; | ||
- | tonetbl[33] = 24149; | ||
- | tonetbl[34] = 13642; | ||
- | tonetbl[35] = 3081; | ||
- | tonetbl[36] = -3745; | ||
- | tonetbl[37] = -4494; | ||
- | tonetbl[38] = 837; | ||
- | tonetbl[39] = 9912; | ||
- | tonetbl[40] = 18947; | ||
- | tonetbl[41] = 24161; | ||
- | tonetbl[42] = 23217; | ||
- | tonetbl[43] = 16119; | ||
- | tonetbl[44] = 5211; | ||
- | tonetbl[45] = -5718; | ||
- | tonetbl[46] = -12878; | ||
- | tonetbl[47] = -13924; | ||
- | tonetbl[48] = -8853; | ||
- | tonetbl[49] = 0; | ||
- | tonetbl[50] = 8853; | ||
- | tonetbl[51] = 13924; | ||
- | tonetbl[52] = 12878; | ||
- | tonetbl[53] = 5718; | ||
- | tonetbl[54] = -5211; | ||
- | tonetbl[55] = -16119; | ||
- | tonetbl[56] = -23217; | ||
- | tonetbl[57] = -24161; | ||
- | tonetbl[58] = -18947; | ||
- | tonetbl[59] = -9912; | ||
- | tonetbl[60] = -837; | ||
- | tonetbl[61] = 4494; | ||
- | tonetbl[62] = 3745; | ||
- | tonetbl[63] = -3081; | ||
- | tonetbl[64] = -13642; | ||
- | tonetbl[65] = -24149; | ||
- | tonetbl[66] = -30814; | ||
- | tonetbl[67] = -31295; | ||
- | tonetbl[68] = -25590; | ||
- | tonetbl[69] = -16037; | ||
- | tonetbl[70] = -6421; | ||
- | tonetbl[71] = -527; | ||
- | tonetbl[72] = -692; | ||
- | tonetbl[73] = -6918; | ||
- | tonetbl[74] = -16863; | ||
- | tonetbl[75] = -26741; | ||
- | tonetbl[76] = -32767; | ||
- | tonetbl[77] = -32601; | ||
- | tonetbl[78] = -26244; | ||
- | tonetbl[79] = -16037; | ||
- | tonetbl[80] = -5767; | ||
- | tonetbl[81] = 780; | ||
- | tonetbl[82] = 1260; | ||
- | tonetbl[83] = -4326; | ||
- | tonetbl[84] = -13642; | ||
- | tonetbl[85] = -22905; | ||
- | tonetbl[86] = -28330; | ||
- | tonetbl[87] = -27581; | ||
- | tonetbl[88] = -20660; | ||
- | tonetbl[89] = -9912; | ||
- | tonetbl[90] = 876; | ||
- | tonetbl[91] = 7914; | ||
- | tonetbl[92] = 8858; | ||
- | tonetbl[93] = 3704; | ||
- | tonetbl[94] = -5211; | ||
- | tonetbl[95] = -14105; | ||
- | tonetbl[96] = -19197; | ||
- | tonetbl[97] = -18151; | ||
- | tonetbl[98] = -10970; | ||
- | tonetbl[99] = 0; | ||
- | end | ||
- | |||
- | //Assign the output to the value in the lookup table | ||
- | //pointed to by toneptr. | ||
- | assign dout = tonetbl[toneptr]; | ||
- | |||
- | //Increment through the tone lookup table and wrap back | ||
- | //to zero when at the end. | ||
- | always @(posedge clk) begin | ||
- | if(en) begin | ||
- | if(toneptr == 7'd99) begin | ||
- | toneptr <= 7'd0; | ||
- | end | ||
- | else begin | ||
- | toneptr <= toneptr + 1'b1; | ||
- | end | ||
- | end | ||
- | end | ||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | ##### FIR_Filter.v | ||
- | <code verilog> | ||
- | |||
- | `define FILT_LENGTH 16 | ||
- | |||
- | module FIR_Filter( | ||
- | input clk, | ||
- | input en, | ||
- | input [15:0]din, | ||
- | output [15:0]dout | ||
- | ); | ||
- | |||
- | reg signed [15:0]coeff[`FILT_LENGTH/2-1:0]; //Filter coefficients. | ||
- | reg signed [15:0]delay_line[`FILT_LENGTH-1:0]; //Input delay line. | ||
- | wire [31:0]accum; //Accumulator for output filter calculation. | ||
- | integer i; //Initialization integer. | ||
- | genvar c; //Delay line generation variable. | ||
- | | ||
- | //Calculate value in the accumulator. | ||
- | assign accum = (delay_line[0] + delay_line[15]) * coeff[0] + | ||
- | (delay_line[1] + delay_line[14]) * coeff[1] + | ||
- | (delay_line[2] + delay_line[13]) * coeff[2] + | ||
- | (delay_line[3] + delay_line[12]) * coeff[3] + | ||
- | (delay_line[4] + delay_line[11]) * coeff[4] + | ||
- | (delay_line[5] + delay_line[10]) * coeff[5] + | ||
- | (delay_line[6] + delay_line[9]) * coeff[6] + | ||
- | (delay_line[7] + delay_line[8]) * coeff[7]; | ||
- | |||
- | //Assign upper 16-bits to output. | ||
- | assign dout = accum[31:16]; | ||
- | |||
- | initial begin | ||
- | //Load the filter coefficients. | ||
- | coeff[0] = 16'd2552; | ||
- | coeff[1] = 16'd4557; | ||
- | coeff[2] = 16'd5051; | ||
- | coeff[3] = 16'd8006; | ||
- | coeff[4] = 16'd9265; | ||
- | coeff[5] = 16'd11427; | ||
- | coeff[6] = 16'd12396; | ||
- | coeff[7] = 16'd13200; | ||
- | |||
- | //Initialize delay line. | ||
- | for(i = 0; i < `FILT_LENGTH; i = i+1'b1) begin | ||
- | delay_line[i] = 16'd0; | ||
- | end | ||
- | end | ||
- | | ||
- | //Advance the data through the delay line every clock cycle. | ||
- | generate | ||
- | for (c = `FILT_LENGTH-1; c > 0; c = c - 1) begin: inc_delay | ||
- | always @(posedge clk) begin | ||
- | if(en) delay_line[c] <= delay_line[c-1]; | ||
- | end | ||
- | end | ||
- | endgenerate | ||
- | | ||
- | //Update with input data. | ||
- | always @(posedge clk) begin | ||
- | if(en) delay_line[0] <= din; | ||
- | end | ||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | ##### clk_en.v | ||
- | <code verilog> | ||
- | |||
- | module clk_en( | ||
- | input clk, | ||
- | output reg en = 1'b0 | ||
- | ); | ||
- | |||
- | reg [15:0]en_counter = 16'h0; | ||
- | | ||
- | always @(posedge clk) begin | ||
- | if(en_counter == 16'd449) begin | ||
- | en_counter <= 16'h0; | ||
- | en <= 1'b1; | ||
- | end | ||
- | else begin | ||
- | en_counter <= en_counter + 1'b1; | ||
- | en <= 1'b0; | ||
- | end | ||
- | end | ||
- | |||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | ##### lfsr.v | ||
- | <code verilog> | ||
- | |||
- | `timescale 1ns / 1ps | ||
- | |||
- | module lfsr( | ||
- | input clk, | ||
- | input en, | ||
- | input rst, | ||
- | output [15:0]lfsr_out | ||
- | ); | ||
- | | ||
- | //Create a 16-bit linear feedback shift register with | ||
- | //maximal polynomial x^16 + x^14 + x^13 + x^11 + 1. | ||
- | reg [15:0]lfsr = 16'd1; | ||
- | wire feedback; | ||
- | | ||
- | assign feedback = ((lfsr[15] ^ lfsr[13]) ^ lfsr[12]) ^ lfsr[10]; | ||
- | assign lfsr_out = lfsr; | ||
- | | ||
- | //Update the linear feedback shift register. | ||
- | always @(posedge clk) begin | ||
- | if(rst) lfsr <= 16'd1; | ||
- | else if(en) lfsr <= {lfsr[14:0], feedback}; | ||
- | end | ||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | ##### TB_LMS_Adapt.v | ||
- | <code verilog> | ||
- | |||
- | module TB_LMS_Adapt; | ||
- | |||
- | reg clk = 1'b0; | ||
- | reg [7:0]sw = 1'b1; | ||
- | wire [7:0]JA; | ||
- | | ||
- | wire [15:0]d; | ||
- | wire [15:0]y; | ||
- | wire [15:0]e; | ||
- | wire [15:0]n1; | ||
- | | ||
- | filter_top uut(.clk(clk), .sw(sw), .JA(JA)); | ||
- | | ||
- | assign d = uut.fout; | ||
- | assign y = uut.aout; | ||
- | assign e = uut.err; | ||
- | assign n1 = uut.af.n1[0]; | ||
- | |||
- | always #5 clk = ~clk; | ||
- | | ||
- | initial begin | ||
- | //#20000000 sw[0] = 1'b1; | ||
- | //#40000 sw[0] = 1'b1; | ||
- | end | ||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | #### 块FIR滤波器 | ||
- | 块FIR滤波器的创建是对块概念的初步测试,因为其计算块比LMS滤波器计算块简单得多。滤波器的核心由四个计算模块组成,每个时钟周期对四个数据样本进行操作。\\ | ||
- | {{ ::block_fir_filter.png |}} | ||
- | ##### Block_FIR.v | ||
- | <code verilog> | ||
- | |||
- | `timescale 1ns / 1ps | ||
- | |||
- | module Block_FIR( | ||
- | input clk, | ||
- | input en, | ||
- | input signed [15:0]x0_in, | ||
- | input signed [15:0]x1_in, | ||
- | input signed [15:0]x2_in, | ||
- | input signed [15:0]x3_in, | ||
- | output reg signed [15:0]x0_out = 16'd0, | ||
- | output reg signed [15:0]x1_out = 16'd0, | ||
- | output reg signed [15:0]x2_out = 16'd0, | ||
- | output reg signed [15:0]x3_out = 16'd0, | ||
- | output signed [15:0]u0, | ||
- | output signed [15:0]u1, | ||
- | output signed [15:0]u2, | ||
- | output signed [15:0]u3 | ||
- | ); | ||
- | | ||
- | //Filter coefficients. | ||
- | parameter b0 = 16'd1; | ||
- | parameter b1 = 16'd1; | ||
- | parameter b2 = 16'd1; | ||
- | parameter b3 = 16'd1; | ||
- | | ||
- | //Coefficient registers. | ||
- | reg signed [15:0]_b0 = b0; | ||
- | reg signed [15:0]_b1 = b1; | ||
- | reg signed [15:0]_b2 = b2; | ||
- | reg signed [15:0]_b3 = b3; | ||
- | | ||
- | //Register unit. | ||
- | always @(posedge clk) begin | ||
- | if(en) begin | ||
- | x0_out <= x0_in; | ||
- | x1_out <= x1_in; | ||
- | x2_out <= x2_in; | ||
- | x3_out <= x3_in; | ||
- | end | ||
- | end | ||
- | | ||
- | /******************************IPC1******************************/ | ||
- | //Multiplier outputs. | ||
- | wire signed [31:0]IPC1_mult0; | ||
- | wire signed [31:0]IPC1_mult1; | ||
- | wire signed [31:0]IPC1_mult2; | ||
- | wire signed [31:0]IPC1_mult3; | ||
- | | ||
- | //Adder outputs. | ||
- | wire signed [31:0]IPC1_add0; | ||
- | wire signed [31:0]IPC1_add1; | ||
- | wire signed [31:0]IPC1_out; | ||
- | | ||
- | //Multiply inputs with coefficients. | ||
- | assign IPC1_mult0 = x3_in * _b0; | ||
- | assign IPC1_mult1 = x2_in * _b1; | ||
- | assign IPC1_mult2 = x1_in * _b2; | ||
- | assign IPC1_mult3 = x0_in * _b3; | ||
- | | ||
- | //Add multiplied values together. | ||
- | assign IPC1_add0 = IPC1_mult0 + IPC1_mult1; | ||
- | assign IPC1_add1 = IPC1_mult2 + IPC1_mult3; | ||
- | assign IPC1_out = IPC1_add0 + IPC1_add1; | ||
- | | ||
- | //Assign output. | ||
- | assign u3 = IPC1_out[31:16]; | ||
- | | ||
- | /******************************IPC2******************************/ | ||
- | //Multiplier outputs. | ||
- | wire signed [31:0]IPC2_mult0; | ||
- | wire signed [31:0]IPC2_mult1; | ||
- | wire signed [31:0]IPC2_mult2; | ||
- | wire signed [31:0]IPC2_mult3; | ||
- | | ||
- | //Adder outputs. | ||
- | wire signed [31:0]IPC2_add0; | ||
- | wire signed [31:0]IPC2_add1; | ||
- | wire signed [31:0]IPC2_out; | ||
- | | ||
- | //Multiply inputs with coefficients. | ||
- | assign IPC2_mult0 = x2_in * _b0; | ||
- | assign IPC2_mult1 = x1_in * _b1; | ||
- | assign IPC2_mult2 = x0_in * _b2; | ||
- | assign IPC2_mult3 = x3_out * _b3; | ||
- | | ||
- | //Add multiplied values together. | ||
- | assign IPC2_add0 = IPC2_mult0 + IPC2_mult1; | ||
- | assign IPC2_add1 = IPC2_mult2 + IPC2_mult3; | ||
- | assign IPC2_out = IPC2_add0 + IPC2_add1; | ||
- | | ||
- | //Assign output. | ||
- | assign u2 = IPC2_out[31:16]; | ||
- | | ||
- | /******************************IPC3******************************/ | ||
- | //Multiplier outputs. | ||
- | wire signed [31:0]IPC3_mult0; | ||
- | wire signed [31:0]IPC3_mult1; | ||
- | wire signed [31:0]IPC3_mult2; | ||
- | wire signed [31:0]IPC3_mult3; | ||
- | | ||
- | //Adder outputs. | ||
- | wire signed [31:0]IPC3_add0; | ||
- | wire signed [31:0]IPC3_add1; | ||
- | wire signed [31:0]IPC3_out; | ||
- | | ||
- | //Multiply inputs with coefficients. | ||
- | assign IPC3_mult0 = x1_in * _b0; | ||
- | assign IPC3_mult1 = x0_in * _b1; | ||
- | assign IPC3_mult2 = x3_out * _b2; | ||
- | assign IPC3_mult3 = x2_out * _b3; | ||
- | | ||
- | //Add multiplied values together. | ||
- | assign IPC3_add0 = IPC3_mult0 + IPC3_mult1; | ||
- | assign IPC3_add1 = IPC3_mult2 + IPC3_mult3; | ||
- | assign IPC3_out = IPC3_add0 + IPC3_add1; | ||
- | | ||
- | //Assign output. | ||
- | assign u1 = IPC3_out[31:16]; | ||
- | | ||
- | /******************************IPC4******************************/ | ||
- | //Multiplier outputs. | ||
- | wire signed [31:0]IPC4_mult0; | ||
- | wire signed [31:0]IPC4_mult1; | ||
- | wire signed [31:0]IPC4_mult2; | ||
- | wire signed [31:0]IPC4_mult3; | ||
- | | ||
- | //Adder outputs. | ||
- | wire signed [31:0]IPC4_add0; | ||
- | wire signed [31:0]IPC4_add1; | ||
- | wire signed [31:0]IPC4_out; | ||
- | | ||
- | //Multiply inputs with coefficients. | ||
- | assign IPC4_mult0 = x0_in * _b0; | ||
- | assign IPC4_mult1 = x3_out * _b1; | ||
- | assign IPC4_mult2 = x2_out * _b2; | ||
- | assign IPC4_mult3 = x1_out * _b3; | ||
- | | ||
- | //Add multiplied values together. | ||
- | assign IPC4_add0 = IPC4_mult0 + IPC4_mult1; | ||
- | assign IPC4_add1 = IPC4_mult2 + IPC4_mult3; | ||
- | assign IPC4_out = IPC4_add0 + IPC4_add1; | ||
- | | ||
- | //Assign output. | ||
- | assign u0 = IPC4_out[31:16]; | ||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | ##### Block_FIR_Top.v | ||
- | <code verilog> | ||
- | |||
- | `timescale 1ns / 1ps | ||
- | |||
- | module Block_FIR_Top( | ||
- | input clk, | ||
- | input [7:0]sw, | ||
- | output [7:0]JA | ||
- | ); | ||
- | | ||
- | wire clk_100MHz; | ||
- | wire clk_25MHz; | ||
- | wire en; | ||
- | | ||
- | wire signed [15:0]tonegen_out; | ||
- | | ||
- | //Data divider outputs. | ||
- | wire en_out; | ||
- | wire signed [15:0]d0_out; | ||
- | wire signed [15:0]d1_out; | ||
- | wire signed [15:0]d2_out; | ||
- | wire signed [15:0]d3_out; | ||
- | | ||
- | //FIR f1 outputs | ||
- | wire signed [15:0]f1_x0_out; | ||
- | wire signed [15:0]f1_x1_out; | ||
- | wire signed [15:0]f1_x2_out; | ||
- | wire signed [15:0]f1_x3_out; | ||
- | wire signed [15:0]f1_u0; | ||
- | wire signed [15:0]f1_u1; | ||
- | wire signed [15:0]f1_u2; | ||
- | wire signed [15:0]f1_u3; | ||
- | | ||
- | //FIR f2 outputs | ||
- | wire signed [15:0]f2_x0_out; | ||
- | wire signed [15:0]f2_x1_out; | ||
- | wire signed [15:0]f2_x2_out; | ||
- | wire signed [15:0]f2_x3_out; | ||
- | wire signed [15:0]f2_u0; | ||
- | wire signed [15:0]f2_u1; | ||
- | wire signed [15:0]f2_u2; | ||
- | wire signed [15:0]f2_u3; | ||
- | | ||
- | //FIR f3 outputs | ||
- | wire signed [15:0]f3_x0_out; | ||
- | wire signed [15:0]f3_x1_out; | ||
- | wire signed [15:0]f3_x2_out; | ||
- | wire signed [15:0]f3_x3_out; | ||
- | wire signed [15:0]f3_u0; | ||
- | wire signed [15:0]f3_u1; | ||
- | wire signed [15:0]f3_u2; | ||
- | wire signed [15:0]f3_u3; | ||
- | | ||
- | //FIR f4 outputs | ||
- | wire signed [15:0]f4_x0_out; | ||
- | wire signed [15:0]f4_x1_out; | ||
- | wire signed [15:0]f4_x2_out; | ||
- | wire signed [15:0]f4_x3_out; | ||
- | wire signed [15:0]f4_u0; | ||
- | wire signed [15:0]f4_u1; | ||
- | wire signed [15:0]f4_u2; | ||
- | wire signed [15:0]f4_u3; | ||
- | | ||
- | //Block filter outputs. | ||
- | wire signed [15:0]y0; | ||
- | wire signed [15:0]y1; | ||
- | wire signed [15:0]y2; | ||
- | wire signed [15:0]y3; | ||
- | | ||
- | wire [15:0]serial_dout; //Serialized output. | ||
- | wire [15:0]mout; //Selected output. | ||
- | | ||
- | assign en = 1'b1; | ||
- | | ||
- | clk_wiz_0 cw(.clk_in1(clk), .clk_out1(clk_100MHz), .clk_out2(clk_25MHz)); | ||
- | ToneGen tg(.clk(clk_100MHz), .en(en), .dout(tonegen_out)); | ||
- | Data_Div4 dd(.clk(clk_100MHz), .en(en), .din(tonegen_out), .en_out(en_out), | ||
- | .d0_out(d0_out), .d1_out(d1_out), .d2_out(d2_out), .d3_out(d3_out)); | ||
- | |||
- | //Build 16-tap block FIR filter. | ||
- | Block_FIR #(.b0(16'd2320), .b1(16'd4143), .b2(16'd4592), .b3(16'd7278))f1(.clk(clk_25MHz), .en(en), | ||
- | .x0_in(d0_out), .x1_in(d1_out), .x2_in(d2_out), .x3_in(d3_out), | ||
- | .x0_out(f1_x0_out), .x1_out(f1_x1_out), .x2_out(f1_x2_out), .x3_out(f1_x3_out), | ||
- | .u0(f1_u0), .u1(f1_u1), .u2(f1_u2), .u3(f1_u3)); | ||
- | | ||
- | Block_FIR #(.b0(16'd8423), .b1(16'd10389), .b2(16'd11269), .b3(16'd12000))f2(.clk(clk_25MHz), .en(en), | ||
- | .x0_in(f1_x0_out), .x1_in(f1_x1_out), .x2_in(f1_x2_out), .x3_in(f1_x3_out), | ||
- | .x0_out(f2_x0_out), .x1_out(f2_x1_out), .x2_out(f2_x2_out), .x3_out(f2_x3_out), | ||
- | .u0(f2_u0), .u1(f2_u1), .u2(f2_u2), .u3(f2_u3)); | ||
- | |||
- | Block_FIR #(.b0(16'd12000), .b1(16'd11269), .b2(16'd10389), .b3(16'd8423))f3(.clk(clk_25MHz), .en(en), | ||
- | .x0_in(f2_x0_out), .x1_in(f2_x1_out), .x2_in(f2_x2_out), .x3_in(f2_x3_out), | ||
- | .x0_out(f3_x0_out), .x1_out(f3_x1_out), .x2_out(f3_x2_out), .x3_out(f3_x3_out), | ||
- | .u0(f3_u0), .u1(f3_u1), .u2(f3_u2), .u3(f3_u3)); | ||
- | |||
- | Block_FIR #(.b0(16'd7278), .b1(16'd4592), .b2(16'd4143), .b3(16'd2320))f4(.clk(clk_25MHz), .en(en), | ||
- | .x0_in(f3_x0_out), .x1_in(f3_x1_out), .x2_in(f3_x2_out), .x3_in(f3_x3_out), | ||
- | .x0_out(f4_x0_out), .x1_out(f4_x1_out), .x2_out(f4_x2_out), .x3_out(f4_x3_out), | ||
- | .u0(f4_u0), .u1(f4_u1), .u2(f4_u2), .u3(f4_u3)); | ||
- | | ||
- | //Add outputs together. | ||
- | assign y0 = f1_u0 + f2_u0 + f3_u0 + f4_u0; | ||
- | assign y1 = f1_u1 + f2_u1 + f3_u1 + f4_u1; | ||
- | assign y2 = f1_u2 + f2_u2 + f3_u2 + f4_u2; | ||
- | assign y3 = f1_u3 + f2_u3 + f3_u3 + f4_u3; | ||
- | | ||
- | //Serialize the output data. | ||
- | Data_Mult4 dm(.clk(clk_100MHz), .en(en), .d0_in(y0), .d1_in(y1), .d2_in(y2), .d3_in(y3), .dout(serial_dout)); | ||
- | | ||
- | //Choose filtered or unfiltered output based on sw0. | ||
- | assign mout = sw[0] ? serial_dout : tonegen_out; | ||
- | | ||
- | //Take only the upper 8 bits and make it unsigned. | ||
- | //assign JA = mout[15:8] + 8'd128; | ||
- | assign {JA[3:0], JA[7:4]} = mout[15:8] + 8'd128; | ||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | ##### ToneGen.v | ||
- | <code verilog> | ||
- | |||
- | `timescale 1ns/1ps | ||
- | |||
- | module ToneGen( | ||
- | input clk, | ||
- | input en, | ||
- | output [15:0]dout | ||
- | ); | ||
- | |||
- | //Tone generation data. At a 44KHz sampling rate, the lookup table | ||
- | //generates a 440Hz and 4.4KHz tone mixed together. | ||
- | reg [15:0]tonetbl[99:0]; | ||
- | | ||
- | //Pointer into the tone table. | ||
- | reg [6:0]toneptr = 7'h00; | ||
- | | ||
- | initial begin | ||
- | tonetbl[0] = 10970; | ||
- | tonetbl[1] = 18151; | ||
- | tonetbl[2] = 19197; | ||
- | tonetbl[3] = 14105; | ||
- | tonetbl[4] = 5211; | ||
- | tonetbl[5] = -3704; | ||
- | tonetbl[6] = -8858; | ||
- | tonetbl[7] = -7914; | ||
- | tonetbl[8] = -876; | ||
- | tonetbl[9] = 9912; | ||
- | tonetbl[10] = 20660; | ||
- | tonetbl[11] = 27581; | ||
- | tonetbl[12] = 28330; | ||
- | tonetbl[13] = 22905; | ||
- | tonetbl[14] = 13642; | ||
- | tonetbl[15] = 4326; | ||
- | tonetbl[16] = -1260; | ||
- | tonetbl[17] = -780; | ||
- | tonetbl[18] = 5767; | ||
- | tonetbl[19] = 16037; | ||
- | tonetbl[20] = 26244; | ||
- | tonetbl[21] = 32601; | ||
- | tonetbl[22] = 32767; | ||
- | tonetbl[23] = 26741; | ||
- | tonetbl[24] = 16863; | ||
- | tonetbl[25] = 6918; | ||
- | tonetbl[26] = 692; | ||
- | tonetbl[27] = 527; | ||
- | tonetbl[28] = 6421; | ||
- | tonetbl[29] = 16037; | ||
- | tonetbl[30] = 25590; | ||
- | tonetbl[31] = 31295; | ||
- | tonetbl[32] = 30814; | ||
- | tonetbl[33] = 24149; | ||
- | tonetbl[34] = 13642; | ||
- | tonetbl[35] = 3081; | ||
- | tonetbl[36] = -3745; | ||
- | tonetbl[37] = -4494; | ||
- | tonetbl[38] = 837; | ||
- | tonetbl[39] = 9912; | ||
- | tonetbl[40] = 18947; | ||
- | tonetbl[41] = 24161; | ||
- | tonetbl[42] = 23217; | ||
- | tonetbl[43] = 16119; | ||
- | tonetbl[44] = 5211; | ||
- | tonetbl[45] = -5718; | ||
- | tonetbl[46] = -12878; | ||
- | tonetbl[47] = -13924; | ||
- | tonetbl[48] = -8853; | ||
- | tonetbl[49] = 0; | ||
- | tonetbl[50] = 8853; | ||
- | tonetbl[51] = 13924; | ||
- | tonetbl[52] = 12878; | ||
- | tonetbl[53] = 5718; | ||
- | tonetbl[54] = -5211; | ||
- | tonetbl[55] = -16119; | ||
- | tonetbl[56] = -23217; | ||
- | tonetbl[57] = -24161; | ||
- | tonetbl[58] = -18947; | ||
- | tonetbl[59] = -9912; | ||
- | tonetbl[60] = -837; | ||
- | tonetbl[61] = 4494; | ||
- | tonetbl[62] = 3745; | ||
- | tonetbl[63] = -3081; | ||
- | tonetbl[64] = -13642; | ||
- | tonetbl[65] = -24149; | ||
- | tonetbl[66] = -30814; | ||
- | tonetbl[67] = -31295; | ||
- | tonetbl[68] = -25590; | ||
- | tonetbl[69] = -16037; | ||
- | tonetbl[70] = -6421; | ||
- | tonetbl[71] = -527; | ||
- | tonetbl[72] = -692; | ||
- | tonetbl[73] = -6918; | ||
- | tonetbl[74] = -16863; | ||
- | tonetbl[75] = -26741; | ||
- | tonetbl[76] = -32767; | ||
- | tonetbl[77] = -32601; | ||
- | tonetbl[78] = -26244; | ||
- | tonetbl[79] = -16037; | ||
- | tonetbl[80] = -5767; | ||
- | tonetbl[81] = 780; | ||
- | tonetbl[82] = 1260; | ||
- | tonetbl[83] = -4326; | ||
- | tonetbl[84] = -13642; | ||
- | tonetbl[85] = -22905; | ||
- | tonetbl[86] = -28330; | ||
- | tonetbl[87] = -27581; | ||
- | tonetbl[88] = -20660; | ||
- | tonetbl[89] = -9912; | ||
- | tonetbl[90] = 876; | ||
- | tonetbl[91] = 7914; | ||
- | tonetbl[92] = 8858; | ||
- | tonetbl[93] = 3704; | ||
- | tonetbl[94] = -5211; | ||
- | tonetbl[95] = -14105; | ||
- | tonetbl[96] = -19197; | ||
- | tonetbl[97] = -18151; | ||
- | tonetbl[98] = -10970; | ||
- | tonetbl[99] = 0; | ||
- | end | ||
- | |||
- | //Assign the output to the value in the lookup table | ||
- | //pointed to by toneptr. | ||
- | assign dout = tonetbl[toneptr]; | ||
- | |||
- | //Increment through the tone lookup table and wrap back | ||
- | //to zero when at the end. | ||
- | always @(posedge clk) begin | ||
- | if(en) begin | ||
- | if(toneptr == 7'd99) begin | ||
- | toneptr <= 7'd0; | ||
- | end | ||
- | else begin | ||
- | toneptr <= toneptr + 1'b1; | ||
- | end | ||
- | end | ||
- | end | ||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | ##### Data_Div4.v | ||
- | <code verilog> | ||
- | |||
- | `timescale 1ns / 1ps | ||
- | |||
- | module Data_Div4( | ||
- | input clk, | ||
- | input en, | ||
- | input [15:0]din, | ||
- | output reg en_out = 1'b0, | ||
- | output reg [15:0]d0_out = 16'd0, | ||
- | output reg [15:0]d1_out = 16'd0, | ||
- | output reg [15:0]d2_out = 16'd0, | ||
- | output reg [15:0]d3_out = 16'd0 | ||
- | ); | ||
- | | ||
- | reg [1:0]count = 2'd0; | ||
- | | ||
- | //Internal registers for holding data. | ||
- | reg [15:0]d0 = 16'd0; | ||
- | reg [15:0]d1 = 16'd0; | ||
- | reg [15:0]d2 = 16'd0; | ||
- | | ||
- | always @(posedge clk) begin | ||
- | if(en) begin | ||
- | count <= count + 1'b1; | ||
- | | ||
- | if(count == 2'b00) begin | ||
- | d0 <= din; | ||
- | en_out <= 1'b0; | ||
- | end | ||
- | else if(count == 2'b01) begin | ||
- | d1 <= din; | ||
- | en_out <= 1'b0; | ||
- | end | ||
- | else if(count == 2'b10) begin | ||
- | d2 <= din; | ||
- | en_out <= 1'b0; | ||
- | end | ||
- | else begin | ||
- | d0_out <= d0; | ||
- | d1_out <= d1; | ||
- | d2_out <= d2; | ||
- | d3_out <= din; | ||
- | en_out <= 1'b1; | ||
- | end | ||
- | end | ||
- | end | ||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | ##### Data_Mult4.v | ||
- | <code verilog> | ||
- | |||
- | `timescale 1ns / 1ps | ||
- | |||
- | module Data_Mult4( | ||
- | input clk, | ||
- | input en, | ||
- | input [15:0]d0_in, | ||
- | input [15:0]d1_in, | ||
- | input [15:0]d2_in, | ||
- | input [15:0]d3_in, | ||
- | output reg [15:0]dout = 16'd0 | ||
- | ); | ||
- | | ||
- | reg [1:0]count = 2'd0; | ||
- | | ||
- | //Internal registers for holding data. | ||
- | reg [15:0]d0 = 16'd0; | ||
- | reg [15:0]d1 = 16'd0; | ||
- | reg [15:0]d2 = 16'd0; | ||
- | reg [15:0]d3 = 16'd0; | ||
- | | ||
- | always @(posedge clk) begin | ||
- | if(en) begin | ||
- | count <= count + 1'b1; | ||
- | | ||
- | if(count == 2'b00) begin | ||
- | dout <= d0; | ||
- | end | ||
- | else if(count == 2'b01) begin | ||
- | dout <= d1; | ||
- | end | ||
- | else if(count == 2'b10) begin | ||
- | dout <= d2; | ||
- | end | ||
- | else begin | ||
- | d0 <= d0_in; | ||
- | d1 <= d1_in; | ||
- | d2 <= d2_in; | ||
- | d3 <= d3_in; | ||
- | dout <= d3; | ||
- | end | ||
- | end | ||
- | end | ||
- | |||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | ##### Block_FIR_TB.v | ||
- | <code verilog> | ||
- | |||
- | `timescale 1ns / 1ps | ||
- | |||
- | module Block_FIR_TB; | ||
- | reg clk = 1'b0; | ||
- | reg [7:0]sw = 8'd0; | ||
- | wire [7:0]JA; | ||
- | | ||
- | Block_FIR_Top uut(.clk(clk), .sw(sw), .JA(JA)); | ||
- | | ||
- | initial begin | ||
- | #50000 sw = 8'd1; | ||
- | end | ||
- | | ||
- | always #5 clk = ~clk; | ||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | #### LMS过滤器 | ||
- | 最后也是最复杂的过滤器是Block LMS过滤器。它还具有四个计算模块,一次可以处理四个数据样本,但是它具有一个简单的状态机,可以将其操作分成两个时钟周期。一个时钟周期计算输出值,而另一个时钟周期更新权重。\\ | ||
- | {{ ::block_lms_filter.png |}} | ||
- | |||
- | ##### BLMS_Block.v | ||
- | <code verilog> | ||
- | |||
- | `timescale 1ns / 1ps | ||
- | |||
- | module BLMS_Block( | ||
- | input clk, //Filter clock. | ||
- | input x_en, //X registers enable. | ||
- | input w_en, //Weight registers enable. | ||
- | input mux_sel, //MUX selection input. | ||
- | input dmux_sel, //DMUX selection input. | ||
- | | ||
- | input signed [15:0]xin0, // | ||
- | input signed [15:0]xin1, //16-bit Data input. | ||
- | input signed [15:0]xin2, // | ||
- | input signed [15:0]xin3, // | ||
- | | ||
- | input signed [15:0]r0, // | ||
- | input signed [15:0]r1, //Weight adjust input. | ||
- | input signed [15:0]r2, // | ||
- | input signed [15:0]r3, // | ||
- | | ||
- | output signed [15:0]u0, // | ||
- | output signed [15:0]u1, //u output for calculating y. | ||
- | output signed [15:0]u2, // | ||
- | output signed [15:0]u3, // | ||
- | | ||
- | output reg signed [15:0]xout0 = 16'd0, // | ||
- | output reg signed [15:0]xout1 = 16'd0, //Data to cascade | ||
- | output reg signed [15:0]xout2 = 16'd0, //to the next block. | ||
- | output reg signed [15:0]xout3 = 16'd0 // | ||
- | ); | ||
- | | ||
- | //Filter weights. | ||
- | parameter b0 = 16'd0; | ||
- | parameter b1 = 16'd0; | ||
- | parameter b2 = 16'd0; | ||
- | parameter b3 = 16'd0; | ||
- | | ||
- | //Weight registers. | ||
- | reg signed [15:0]_b0 = b0; | ||
- | reg signed [15:0]_b1 = b1; | ||
- | reg signed [15:0]_b2 = b2; | ||
- | reg signed [15:0]_b3 = b3; | ||
- | | ||
- | /*************************Register Unit**************************/ | ||
- | always @(posedge clk) begin | ||
- | if(x_en) begin | ||
- | xout0 <= xin0; | ||
- | xout1 <= xin1; | ||
- | xout2 <= xin2; | ||
- | xout3 <= xin3; | ||
- | end | ||
- | end | ||
- | | ||
- | /******************************IPC1******************************/ | ||
- | //Multiplier inputs. | ||
- | wire signed [15:0]IPC1_mult0_in; | ||
- | wire signed [15:0]IPC1_mult1_in; | ||
- | wire signed [15:0]IPC1_mult2_in; | ||
- | wire signed [15:0]IPC1_mult3_in; | ||
- | | ||
- | //Multiplier outputs. | ||
- | wire signed [31:0]IPC1_mult0_out; | ||
- | wire signed [31:0]IPC1_mult1_out; | ||
- | wire signed [31:0]IPC1_mult2_out; | ||
- | wire signed [31:0]IPC1_mult3_out; | ||
- | | ||
- | //Adder outputs. | ||
- | wire signed [31:0]IPC1_add0; | ||
- | wire signed [31:0]IPC1_add1; | ||
- | wire signed [31:0]IPC1_out; | ||
- | | ||
- | //Do multiplications. | ||
- | assign IPC1_mult0_out = xin3 * IPC1_mult0_in; | ||
- | assign IPC1_mult1_out = xin2 * IPC1_mult1_in; | ||
- | assign IPC1_mult2_out = xin1 * IPC1_mult2_in; | ||
- | assign IPC1_mult3_out = xin0 * IPC1_mult3_in; | ||
- | | ||
- | //Do additions. | ||
- | assign IPC1_add0 = IPC1_mult0_out + IPC1_mult1_out; | ||
- | assign IPC1_add1 = IPC1_mult2_out + IPC1_mult3_out; | ||
- | assign IPC1_out = IPC1_add0 + IPC1_add1; | ||
- | | ||
- | /******************************IPC2******************************/ | ||
- | //Multiplier inputs. | ||
- | wire signed [15:0]IPC2_mult0_in; | ||
- | wire signed [15:0]IPC2_mult1_in; | ||
- | wire signed [15:0]IPC2_mult2_in; | ||
- | wire signed [15:0]IPC2_mult3_in; | ||
- | | ||
- | //Multiplier outputs. | ||
- | wire signed [31:0]IPC2_mult0_out; | ||
- | wire signed [31:0]IPC2_mult1_out; | ||
- | wire signed [31:0]IPC2_mult2_out; | ||
- | wire signed [31:0]IPC2_mult3_out; | ||
- | | ||
- | //Adder outputs. | ||
- | wire signed [31:0]IPC2_add0; | ||
- | wire signed [31:0]IPC2_add1; | ||
- | wire signed [31:0]IPC2_out; | ||
- | | ||
- | //Do multiplications. | ||
- | assign IPC2_mult0_out = xin2 * IPC2_mult0_in; | ||
- | assign IPC2_mult1_out = xin1 * IPC2_mult1_in; | ||
- | assign IPC2_mult2_out = xin0 * IPC2_mult2_in; | ||
- | assign IPC2_mult3_out = xout3 * IPC2_mult3_in; | ||
- | | ||
- | //Do additions. | ||
- | assign IPC2_add0 = IPC2_mult0_out + IPC2_mult1_out; | ||
- | assign IPC2_add1 = IPC2_mult2_out + IPC2_mult3_out; | ||
- | assign IPC2_out = IPC2_add0 + IPC2_add1; | ||
- | | ||
- | /******************************IPC3******************************/ | ||
- | //Multiplier inputs. | ||
- | wire signed [15:0]IPC3_mult0_in; | ||
- | wire signed [15:0]IPC3_mult1_in; | ||
- | wire signed [15:0]IPC3_mult2_in; | ||
- | wire signed [15:0]IPC3_mult3_in; | ||
- | | ||
- | //Multiplier outputs. | ||
- | wire signed [31:0]IPC3_mult0_out; | ||
- | wire signed [31:0]IPC3_mult1_out; | ||
- | wire signed [31:0]IPC3_mult2_out; | ||
- | wire signed [31:0]IPC3_mult3_out; | ||
- | | ||
- | //Adder outputs. | ||
- | wire signed [31:0]IPC3_add0; | ||
- | wire signed [31:0]IPC3_add1; | ||
- | wire signed [31:0]IPC3_out; | ||
- | | ||
- | //Do multiplications. | ||
- | assign IPC3_mult0_out = xin1 * IPC3_mult0_in; | ||
- | assign IPC3_mult1_out = xin0 * IPC3_mult1_in; | ||
- | assign IPC3_mult2_out = xout3 * IPC3_mult2_in; | ||
- | assign IPC3_mult3_out = xout2 * IPC3_mult3_in; | ||
- | | ||
- | //Do additions. | ||
- | assign IPC3_add0 = IPC3_mult0_out + IPC3_mult1_out; | ||
- | assign IPC3_add1 = IPC3_mult2_out + IPC3_mult3_out; | ||
- | assign IPC3_out = IPC3_add0 + IPC3_add1; | ||
- | | ||
- | /******************************IPC4******************************/ | ||
- | //Multiplier inputs. | ||
- | wire signed [15:0]IPC4_mult0_in; | ||
- | wire signed [15:0]IPC4_mult1_in; | ||
- | wire signed [15:0]IPC4_mult2_in; | ||
- | wire signed [15:0]IPC4_mult3_in; | ||
- | | ||
- | //Multiplier outputs. | ||
- | wire signed [31:0]IPC4_mult0_out; | ||
- | wire signed [31:0]IPC4_mult1_out; | ||
- | wire signed [31:0]IPC4_mult2_out; | ||
- | wire signed [31:0]IPC4_mult3_out; | ||
- | | ||
- | //Adder outputs. | ||
- | wire signed [31:0]IPC4_add0; | ||
- | wire signed [31:0]IPC4_add1; | ||
- | wire signed [31:0]IPC4_out; | ||
- | | ||
- | //Do multiplications. | ||
- | assign IPC4_mult0_out = xin0 * IPC4_mult0_in; | ||
- | assign IPC4_mult1_out = xout3 * IPC4_mult1_in; | ||
- | assign IPC4_mult2_out = xout2 * IPC4_mult2_in; | ||
- | assign IPC4_mult3_out = xout1 * IPC4_mult3_in; | ||
- | | ||
- | //Do additions. | ||
- | assign IPC4_add0 = IPC4_mult0_out + IPC4_mult1_out; | ||
- | assign IPC4_add1 = IPC4_mult2_out + IPC4_mult3_out; | ||
- | assign IPC4_out = IPC4_add0 + IPC4_add1; | ||
- | | ||
- | /***************************DMUX Unit****************************/ | ||
- | | ||
- | //DMUX outputs. | ||
- | wire signed [15:0]dmux1_out0; | ||
- | wire signed [15:0]dmux1_out1; | ||
- | wire signed [15:0]dmux2_out0; | ||
- | wire signed [15:0]dmux2_out1; | ||
- | wire signed [15:0]dmux3_out0; | ||
- | wire signed [15:0]dmux3_out1; | ||
- | wire signed [15:0]dmux4_out0; | ||
- | wire signed [15:0]dmux4_out1; | ||
- | | ||
- | //Assign outputs. | ||
- | assign dmux1_out0 = dmux_sel ? 16'd0 : IPC1_out[31:16]; | ||
- | assign dmux1_out1 = dmux_sel ? IPC1_out[31:16] : 16'd0; | ||
- | | ||
- | assign dmux2_out0 = dmux_sel ? 16'd0 : IPC2_out[31:16]; | ||
- | assign dmux2_out1 = dmux_sel ? IPC2_out[31:16] : 16'd0; | ||
- | | ||
- | assign dmux3_out0 = dmux_sel ? 16'd0 : IPC3_out[31:16]; | ||
- | assign dmux3_out1 = dmux_sel ? IPC3_out[31:16] : 16'd0; | ||
- | | ||
- | assign dmux4_out0 = dmux_sel ? 16'd0 : IPC4_out[31:16]; | ||
- | assign dmux4_out1 = dmux_sel ? IPC4_out[31:16] : 16'd0; | ||
- | | ||
- | //Assign u values. | ||
- | assign u3 = dmux1_out1; | ||
- | assign u2 = dmux2_out1; | ||
- | assign u1 = dmux3_out1; | ||
- | assign u0 = dmux4_out1; | ||
- | | ||
- | /****************************WU Unit*****************************/ | ||
- | always @(posedge clk) begin | ||
- | if(w_en) begin | ||
- | _b0 <= _b0 + dmux1_out0; | ||
- | _b1 <= _b1 + dmux2_out0; | ||
- | _b2 <= _b2 + dmux3_out0; | ||
- | _b3 <= _b3 + dmux4_out0; | ||
- | end | ||
- | end | ||
- | | ||
- | /****************************MUX Unit****************************/ | ||
- | //MUX outputs. | ||
- | wire signed [15:0]mux0_out; | ||
- | wire signed [15:0]mux1_out; | ||
- | wire signed [15:0]mux2_out; | ||
- | wire signed [15:0]mux3_out; | ||
- | | ||
- | //Assign MUX outputs. | ||
- | assign mux0_out = mux_sel ? _b0 : r0; | ||
- | assign mux1_out = mux_sel ? _b1 : r1; | ||
- | assign mux2_out = mux_sel ? _b2 : r2; | ||
- | assign mux3_out = mux_sel ? _b3 : r3; | ||
- | | ||
- | //Assign MUX outputs to IPC inputs. | ||
- | assign IPC1_mult0_in = mux0_out; | ||
- | assign IPC2_mult0_in = mux0_out; | ||
- | assign IPC3_mult0_in = mux0_out; | ||
- | assign IPC4_mult0_in = mux0_out; | ||
- | assign IPC1_mult1_in = mux1_out; | ||
- | assign IPC2_mult1_in = mux1_out; | ||
- | assign IPC3_mult1_in = mux1_out; | ||
- | assign IPC4_mult1_in = mux1_out; | ||
- | assign IPC1_mult2_in = mux2_out; | ||
- | assign IPC2_mult2_in = mux2_out; | ||
- | assign IPC3_mult2_in = mux2_out; | ||
- | assign IPC4_mult2_in = mux2_out; | ||
- | assign IPC1_mult3_in = mux3_out; | ||
- | assign IPC2_mult3_in = mux3_out; | ||
- | assign IPC3_mult3_in = mux3_out; | ||
- | assign IPC4_mult3_in = mux3_out; | ||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | ##### BLMS_ECU.v | ||
- | <code verilog> | ||
- | |||
- | `timescale 1ns / 1ps | ||
- | |||
- | module BLMS_ECU( | ||
- | input clk, //Filter clock. | ||
- | input r_en, //Weight adjust registers enable. | ||
- | | ||
- | input signed [15:0]din0, // | ||
- | input signed [15:0]din1, //Desired inputs. | ||
- | input signed [15:0]din2, // | ||
- | input signed [15:0]din3, // | ||
- | | ||
- | input signed [15:0]yin0, // | ||
- | input signed [15:0]yin1, //From filter output. | ||
- | input signed [15:0]yin2, // | ||
- | input signed [15:0]yin3, // | ||
- | | ||
- | output reg signed [15:0]r0 = 16'd0, // | ||
- | output reg signed [15:0]r1 = 16'd0, //Stepped error output. | ||
- | output reg signed [15:0]r2 = 16'd0, // | ||
- | output reg signed [15:0]r3 = 16'd0 // | ||
- | ); | ||
- | | ||
- | //Adder outputs. | ||
- | wire signed [15:0]add_out0; | ||
- | wire signed [15:0]add_out1; | ||
- | wire signed [15:0]add_out2; | ||
- | wire signed [15:0]add_out3; | ||
- | | ||
- | //Mu outputs. | ||
- | wire signed [31:0]mu0; | ||
- | wire signed [31:0]mu1; | ||
- | wire signed [31:0]mu2; | ||
- | wire signed [31:0]mu3; | ||
- | | ||
- | //Assign outputs. | ||
- | assign add_out0 = din0 - yin0; | ||
- | assign add_out1 = din1 - yin1; | ||
- | assign add_out2 = din2 - yin2; | ||
- | assign add_out3 = din3 - yin3; | ||
- | | ||
- | //Multiply error by mu (hard coded). | ||
- | assign mu0 = add_out0 << 15; | ||
- | assign mu1 = add_out1 << 15; | ||
- | assign mu2 = add_out2 << 15; | ||
- | assign mu3 = add_out3 << 15; | ||
- | | ||
- | //Update delay registers. | ||
- | always @(posedge clk) begin | ||
- | if(r_en) begin | ||
- | r0 <= mu0[31:16]; | ||
- | r1 <= mu1[31:16]; | ||
- | r2 <= mu2[31:16]; | ||
- | r3 <= mu3[31:16]; | ||
- | end | ||
- | end | ||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | ##### BLMS_Top.v | ||
- | <code verilog> | ||
- | |||
- | `timescale 1ns / 1ps | ||
- | |||
- | module BLMS_Top( | ||
- | input clk, | ||
- | input [7:0]sw, | ||
- | output [7:0]JA | ||
- | ); | ||
- | | ||
- | wire clk_50MHz; | ||
- | wire clk_25MHz; | ||
- | wire en; | ||
- | | ||
- | wire signed [15:0]tonegen_out; //Output of the tone lookup table. | ||
- | wire signed [15:0]fout; //Output of the FIR filter. | ||
- | wire signed [15:0]lfsr_out; //16-bit Random noise variable. | ||
- | wire signed [9:0]rnd; //10-bit noise. | ||
- | wire signed [15:0]tone_and_noise; //Combination of tone and noise. | ||
- | wire signed [15:0]serial_dout; //Serialized output. | ||
- | | ||
- | //Selected desired output. | ||
- | wire signed [15:0]mout; | ||
- | | ||
- | //Parallelized desired output. | ||
- | wire signed [15:0]dout0; | ||
- | wire signed [15:0]dout1; | ||
- | wire signed [15:0]dout2; | ||
- | wire signed [15:0]dout3; | ||
- | | ||
- | //Parallelized input to BLMS filter. | ||
- | wire signed [15:0]blms_din0; | ||
- | wire signed [15:0]blms_din1; | ||
- | wire signed [15:0]blms_din2; | ||
- | wire signed [15:0]blms_din3; | ||
- | | ||
- | //Stepped error. | ||
- | wire signed [15:0]r0; | ||
- | wire signed [15:0]r1; | ||
- | wire signed [15:0]r2; | ||
- | wire signed [15:0]r3; | ||
- | | ||
- | //BLMS block1 outputs. | ||
- | wire signed [15:0]b1_x0_out; | ||
- | wire signed [15:0]b1_x1_out; | ||
- | wire signed [15:0]b1_x2_out; | ||
- | wire signed [15:0]b1_x3_out; | ||
- | wire signed [15:0]b1_u0; | ||
- | wire signed [15:0]b1_u1; | ||
- | wire signed [15:0]b1_u2; | ||
- | wire signed [15:0]b1_u3; | ||
- | | ||
- | //BLMS block2 outputs. | ||
- | wire signed [15:0]b2_x0_out; | ||
- | wire signed [15:0]b2_x1_out; | ||
- | wire signed [15:0]b2_x2_out; | ||
- | wire signed [15:0]b2_x3_out; | ||
- | wire signed [15:0]b2_u0; | ||
- | wire signed [15:0]b2_u1; | ||
- | wire signed [15:0]b2_u2; | ||
- | wire signed [15:0]b2_u3; | ||
- | | ||
- | //BLMS block3 outputs. | ||
- | wire signed [15:0]b3_x0_out; | ||
- | wire signed [15:0]b3_x1_out; | ||
- | wire signed [15:0]b3_x2_out; | ||
- | wire signed [15:0]b3_x3_out; | ||
- | wire signed [15:0]b3_u0; | ||
- | wire signed [15:0]b3_u1; | ||
- | wire signed [15:0]b3_u2; | ||
- | wire signed [15:0]b3_u3; | ||
- | | ||
- | //BLMS block4 outputs. | ||
- | wire signed [15:0]b4_x0_out; | ||
- | wire signed [15:0]b4_x1_out; | ||
- | wire signed [15:0]b4_x2_out; | ||
- | wire signed [15:0]b4_x3_out; | ||
- | wire signed [15:0]b4_u0; | ||
- | wire signed [15:0]b4_u1; | ||
- | wire signed [15:0]b4_u2; | ||
- | wire signed [15:0]b4_u3; | ||
- | | ||
- | //BLMS filter outputs. | ||
- | wire signed [15:0]y0; | ||
- | wire signed [15:0]y1; | ||
- | wire signed [15:0]y2; | ||
- | wire signed [15:0]y3; | ||
- | | ||
- | reg [1:0]en_counter = 2'b00; | ||
- | | ||
- | //Generate enable signal for BLMS filter. | ||
- | always@(posedge clk_50MHz) begin | ||
- | en_counter <= en_counter + 1'b1; | ||
- | end | ||
- | | ||
- | //Toggle enable signal. | ||
- | assign en = (en_counter == 2'b10|| en_counter == 2'b11) ? 1'b1 : 1'b0; | ||
- | | ||
- | //Instantiate clock generator. | ||
- | clk_wiz_0 clk_wiz(.clk_in1(clk), .clk_out1(clk_50MHz), .clk_out2(clk_25MHz)); | ||
- | | ||
- | //Instantiate tone generator. | ||
- | ToneGen tg(.clk(clk_50MHz), .en(1'b1), .dout(tonegen_out)); | ||
- | |||
- | //Instatiate LFSR for random noise generation. | ||
- | lfsr lr(.clk(clk_50MHz), .en(1'b1), .rst(1'b0), .lfsr_out(lfsr_out)); | ||
- | | ||
- | //Add the random noise to the tone. | ||
- | assign rnd = lfsr_out[15:6]; | ||
- | assign tone_and_noise = tonegen_out + rnd; | ||
- | | ||
- | //Instantiate the FIR filter. | ||
- | FIR_Filter ff(.clk(clk_50MHz), .en(1'b1), .din(tone_and_noise), .dout(fout)); | ||
- | | ||
- | //Choose filtered or unfiltered output based on sw0. | ||
- | assign mout = sw[0] ? fout : tone_and_noise; | ||
- | | ||
- | //Instantiate desired out div 4. | ||
- | Data_Div4 d4_fir(.clk(clk_50MHz), .en(1'b1), .din(mout), .d0_out(dout0), | ||
- | .d1_out(dout1), .d2_out(dout2), .d3_out(dout3)); | ||
- | |||
- | //Instantiate BLMS filter div 4. | ||
- | Data_Div4 d4_blms(.clk(clk_50MHz), .en(1'b1), .din(tone_and_noise), .d0_out(blms_din0), | ||
- | .d1_out(blms_din1), .d2_out(blms_din2), .d3_out(blms_din3)); | ||
- | | ||
- | //Build 16-tap block FIR filter. | ||
- | BLMS_Block b1(.clk(clk_25MHz), .x_en(en), .w_en(en), .mux_sel(~en), .dmux_sel(~en), .xin0(blms_din0), | ||
- | .xin1(blms_din1), .xin2(blms_din2), .xin3(blms_din3), .r0(r0), .r1(r1), | ||
- | .r2(r2), .r3(r3), .u0(b1_u0), .u1(b1_u1), .u2(b1_u2), .u3(b1_u3), | ||
- | .xout0(b1_x0_out), .xout1(b1_x1_out), .xout2(b1_x2_out), .xout3(b1_x3_out)); | ||
- | | ||
- | BLMS_Block b2(.clk(clk_25MHz), .x_en(en), .w_en(en), .mux_sel(~en), .dmux_sel(~en), .xin0(b1_x0_out), | ||
- | .xin1(b1_x1_out), .xin2(b1_x2_out), .xin3(b1_x3_out), .r0(r0), .r1(r1), | ||
- | .r2(r2), .r3(r3), .u0(b2_u0), .u1(b2_u1), .u2(b2_u2), .u3(b2_u3), | ||
- | .xout0(b2_x0_out), .xout1(b2_x1_out), .xout2(b2_x2_out), .xout3(b2_x3_out)); | ||
- | | ||
- | BLMS_Block b3(.clk(clk_25MHz), .x_en(en), .w_en(en), .mux_sel(~en), .dmux_sel(~en), .xin0(b2_x0_out), | ||
- | .xin1(b2_x1_out), .xin2(b2_x2_out), .xin3(b2_x3_out), .r0(r0), .r1(r1), | ||
- | .r2(r2), .r3(r3), .u0(b3_u0), .u1(b3_u1), .u2(b3_u2), .u3(b3_u3), | ||
- | .xout0(b3_x0_out), .xout1(b3_x1_out), .xout2(b3_x2_out), .xout3(b3_x3_out)); | ||
- | |||
- | BLMS_Block b4(.clk(clk_25MHz), .x_en(en), .w_en(en), .mux_sel(~en), .dmux_sel(~en), .xin0(b3_x0_out), | ||
- | .xin1(b3_x1_out), .xin2(b3_x2_out), .xin3(b3_x3_out), .r0(r0), .r1(r1), | ||
- | .r2(r2), .r3(r3), .u0(b4_u0), .u1(b4_u1), .u2(b4_u2), .u3(b4_u3), | ||
- | .xout0(b4_x0_out), .xout1(b4_x1_out), .xout2(b4_x2_out), .xout3(b4_x3_out)); | ||
- | |||
- | //Add outputs together. | ||
- | assign y0 = b1_u0 + b2_u0 + b3_u0 + b4_u0; | ||
- | assign y1 = b1_u1 + b2_u1 + b3_u1 + b4_u1; | ||
- | assign y2 = b1_u2 + b2_u2 + b3_u2 + b4_u2; | ||
- | assign y3 = b1_u3 + b2_u3 + b3_u3 + b4_u3; | ||
- | | ||
- | //Instantiate ECU module. | ||
- | BLMS_ECU be(.clk(clk_25MHz), .r_en(~en), .din0(dout0), .din1(dout1), .din2(dout2), | ||
- | .din3(dout3), .yin0(y0), .yin1(y1), .yin2(y2), .yin3(y3), .r0(r0), .r1(r1), | ||
- | .r2(r2), .r3(r3)); | ||
- | | ||
- | //Serialize the BLMS output. | ||
- | Data_Mult4 dm(.clk(clk_50MHz), .en(1'b1), .d0_in(y0), .d1_in(y1), .d2_in(y2), .d3_in(y3), .dout(serial_dout)); | ||
- | | ||
- | //Take only the upper 8 bits and make it unsigned. | ||
- | assign {JA[3:0], JA[7:4]} = serial_dout[15:8] + 8'd128; | ||
- | //assign JA[7:0] = serial_dout[15:8] + 8'd128; | ||
- | |||
- | //assign {JA[3:0], JA[7:4]} = sw[7:0]; | ||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | ##### ToneGen.v | ||
- | <code verilog> | ||
- | |||
- | `timescale 1ns/1ps | ||
- | |||
- | module ToneGen( | ||
- | input clk, | ||
- | input en, | ||
- | output [15:0]dout | ||
- | ); | ||
- | |||
- | //Tone generation data. At a 44KHz sampling rate, the lookup table | ||
- | //generates a 440Hz and 4.4KHz tone mixed together. | ||
- | reg [15:0]tonetbl[99:0]; | ||
- | | ||
- | //Pointer into the tone table. | ||
- | reg [6:0]toneptr = 7'h00; | ||
- | | ||
- | initial begin | ||
- | tonetbl[0] = 2743; | ||
- | tonetbl[1] = 4538; | ||
- | tonetbl[2] = 4799; | ||
- | tonetbl[3] = 3526; | ||
- | tonetbl[4] = 1303; | ||
- | tonetbl[5] = -926; | ||
- | tonetbl[6] = -2214; | ||
- | tonetbl[7] = -1978; | ||
- | tonetbl[8] = -219; | ||
- | tonetbl[9] = 2478; | ||
- | tonetbl[10] = 5165; | ||
- | tonetbl[11] = 6895; | ||
- | tonetbl[12] = 7083; | ||
- | tonetbl[13] = 5726; | ||
- | tonetbl[14] = 3411; | ||
- | tonetbl[15] = 1082; | ||
- | tonetbl[16] = -315; | ||
- | tonetbl[17] = -195; | ||
- | tonetbl[18] = 1442; | ||
- | tonetbl[19] = 4009; | ||
- | tonetbl[20] = 6561; | ||
- | tonetbl[21] = 8151; | ||
- | tonetbl[22] = 8192; | ||
- | tonetbl[23] = 6685; | ||
- | tonetbl[24] = 4216; | ||
- | tonetbl[25] = 1729; | ||
- | tonetbl[26] = 173; | ||
- | tonetbl[27] = 132; | ||
- | tonetbl[28] = 1605; | ||
- | tonetbl[29] = 4009; | ||
- | tonetbl[30] = 6398; | ||
- | tonetbl[31] = 7824; | ||
- | tonetbl[32] = 7704; | ||
- | tonetbl[33] = 6037; | ||
- | tonetbl[34] = 3411; | ||
- | tonetbl[35] = 770; | ||
- | tonetbl[36] = -936; | ||
- | tonetbl[37] = -1124; | ||
- | tonetbl[38] = 209; | ||
- | tonetbl[39] = 2478; | ||
- | tonetbl[40] = 4737; | ||
- | tonetbl[41] = 6040; | ||
- | tonetbl[42] = 5804; | ||
- | tonetbl[43] = 4030; | ||
- | tonetbl[44] = 1303; | ||
- | tonetbl[45] = -1430; | ||
- | tonetbl[46] = -3219; | ||
- | tonetbl[47] = -3481; | ||
- | tonetbl[48] = -2213; | ||
- | tonetbl[49] = 0; | ||
- | tonetbl[50] = 2213; | ||
- | tonetbl[51] = 3481; | ||
- | tonetbl[52] = 3219; | ||
- | tonetbl[53] = 1430; | ||
- | tonetbl[54] = -1303; | ||
- | tonetbl[55] = -4030; | ||
- | tonetbl[56] = -5804; | ||
- | tonetbl[57] = -6040; | ||
- | tonetbl[58] = -4737; | ||
- | tonetbl[59] = -2478; | ||
- | tonetbl[60] = -209; | ||
- | tonetbl[61] = 1124; | ||
- | tonetbl[62] = 936; | ||
- | tonetbl[63] = -770; | ||
- | tonetbl[64] = -3411; | ||
- | tonetbl[65] = -6037; | ||
- | tonetbl[66] = -7704; | ||
- | tonetbl[67] = -7824; | ||
- | tonetbl[68] = -6398; | ||
- | tonetbl[69] = -4009; | ||
- | tonetbl[70] = -1605; | ||
- | tonetbl[71] = -132; | ||
- | tonetbl[72] = -173; | ||
- | tonetbl[73] = -1729; | ||
- | tonetbl[74] = -4216; | ||
- | tonetbl[75] = -6685; | ||
- | tonetbl[76] = -8192; | ||
- | tonetbl[77] = -8151; | ||
- | tonetbl[78] = -6561; | ||
- | tonetbl[79] = -4009; | ||
- | tonetbl[80] = -1442; | ||
- | tonetbl[81] = 195; | ||
- | tonetbl[82] = 315; | ||
- | tonetbl[83] = -1082; | ||
- | tonetbl[84] = -3411; | ||
- | tonetbl[85] = -5726; | ||
- | tonetbl[86] = -7083; | ||
- | tonetbl[87] = -6895; | ||
- | tonetbl[88] = -5165; | ||
- | tonetbl[89] = -2478; | ||
- | tonetbl[90] = 219; | ||
- | tonetbl[91] = 1978; | ||
- | tonetbl[92] = 2214; | ||
- | tonetbl[93] = 926; | ||
- | tonetbl[94] = -1303; | ||
- | tonetbl[95] = -3526; | ||
- | tonetbl[96] = -4799; | ||
- | tonetbl[97] = -4538; | ||
- | tonetbl[98] = -2743; | ||
- | tonetbl[99] = 0; | ||
- | end | ||
- | |||
- | //Assign the output to the value in the lookup table | ||
- | //pointed to by toneptr. | ||
- | assign dout = tonetbl[toneptr]; | ||
- | |||
- | //Increment through the tone lookup table and wrap back | ||
- | //to zero when at the end. | ||
- | always @(posedge clk) begin | ||
- | if(en) begin | ||
- | if(toneptr == 7'd99) begin | ||
- | toneptr <= 7'd0; | ||
- | end | ||
- | else begin | ||
- | toneptr <= toneptr + 1'b1; | ||
- | end | ||
- | end | ||
- | end | ||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | ##### Data_Div4.v | ||
- | <code verilog> | ||
- | |||
- | `timescale 1ns / 1ps | ||
- | |||
- | module Data_Div4( | ||
- | input clk, | ||
- | input en, | ||
- | input [15:0]din, | ||
- | output reg en_out = 1'b0, | ||
- | output reg [15:0]d0_out = 16'd0, | ||
- | output reg [15:0]d1_out = 16'd0, | ||
- | output reg [15:0]d2_out = 16'd0, | ||
- | output reg [15:0]d3_out = 16'd0 | ||
- | ); | ||
- | | ||
- | reg [1:0]count = 2'd0; | ||
- | | ||
- | //Internal registers for holding data. | ||
- | reg [15:0]d0 = 16'd0; | ||
- | reg [15:0]d1 = 16'd0; | ||
- | reg [15:0]d2 = 16'd0; | ||
- | | ||
- | always @(posedge clk) begin | ||
- | if(en) begin | ||
- | count <= count + 1'b1; | ||
- | | ||
- | if(count == 2'b00) begin | ||
- | d0 <= din; | ||
- | en_out <= 1'b0; | ||
- | end | ||
- | else if(count == 2'b01) begin | ||
- | d1 <= din; | ||
- | en_out <= 1'b0; | ||
- | end | ||
- | else if(count == 2'b10) begin | ||
- | d2 <= din; | ||
- | en_out <= 1'b0; | ||
- | end | ||
- | else begin | ||
- | d0_out <= d0; | ||
- | d1_out <= d1; | ||
- | d2_out <= d2; | ||
- | d3_out <= din; | ||
- | en_out <= 1'b1; | ||
- | end | ||
- | end | ||
- | end | ||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | ##### Data_Mult4.v | ||
- | <code verilog> | ||
- | |||
- | `timescale 1ns / 1ps | ||
- | |||
- | module Data_Mult4( | ||
- | input clk, | ||
- | input en, | ||
- | input [15:0]d0_in, | ||
- | input [15:0]d1_in, | ||
- | input [15:0]d2_in, | ||
- | input [15:0]d3_in, | ||
- | output reg [15:0]dout = 16'd0 | ||
- | ); | ||
- | | ||
- | reg [1:0]count = 2'd0; | ||
- | | ||
- | //Internal registers for holding data. | ||
- | reg [15:0]d0 = 16'd0; | ||
- | reg [15:0]d1 = 16'd0; | ||
- | reg [15:0]d2 = 16'd0; | ||
- | reg [15:0]d3 = 16'd0; | ||
- | | ||
- | always @(posedge clk) begin | ||
- | if(en) begin | ||
- | count <= count + 1'b1; | ||
- | | ||
- | if(count == 2'b00) begin | ||
- | d0 <= d0_in; | ||
- | d1 <= d1_in; | ||
- | d2 <= d2_in; | ||
- | d3 <= d3_in; | ||
- | dout <= d3; | ||
- | end | ||
- | else if(count == 2'b01) begin | ||
- | dout <= d0; | ||
- | end | ||
- | else if(count == 2'b10) begin | ||
- | dout <= d1; | ||
- | end | ||
- | else begin | ||
- | | ||
- | dout <= d2; | ||
- | end | ||
- | end | ||
- | end | ||
- | |||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | ##### FIR_Filter.v | ||
- | <code verilog> | ||
- | |||
- | `timescale 1ns / 1ps | ||
- | |||
- | `define FILT_LENGTH 16 | ||
- | |||
- | module FIR_Filter( | ||
- | input clk, | ||
- | input en, | ||
- | input [15:0]din, | ||
- | output [15:0]dout | ||
- | ); | ||
- | |||
- | reg signed [15:0]coeff[`FILT_LENGTH/2-1:0]; //Filter coefficients. | ||
- | reg signed [15:0]delay_line[`FILT_LENGTH-1:0]; //Input delay line. | ||
- | wire [31:0]accum; //Accumulator for output filter calculation. | ||
- | integer i; //Initialization integer. | ||
- | genvar c; //Delay line generation variable. | ||
- | | ||
- | //Calculate value in the accumulator. | ||
- | assign accum = (delay_line[0] + delay_line[15]) * coeff[0] + | ||
- | (delay_line[1] + delay_line[14]) * coeff[1] + | ||
- | (delay_line[2] + delay_line[13]) * coeff[2] + | ||
- | (delay_line[3] + delay_line[12]) * coeff[3] + | ||
- | (delay_line[4] + delay_line[11]) * coeff[4] + | ||
- | (delay_line[5] + delay_line[10]) * coeff[5] + | ||
- | (delay_line[6] + delay_line[9]) * coeff[6] + | ||
- | (delay_line[7] + delay_line[8]) * coeff[7]; | ||
- | |||
- | //Assign upper 16-bits to output. | ||
- | assign dout = accum[31:16]; | ||
- | |||
- | initial begin | ||
- | //Load the filter coefficients. | ||
- | coeff[0] = 16'd2552; | ||
- | coeff[1] = 16'd4557; | ||
- | coeff[2] = 16'd5051; | ||
- | coeff[3] = 16'd8006; | ||
- | coeff[4] = 16'd9265; | ||
- | coeff[5] = 16'd11427; | ||
- | coeff[6] = 16'd12396; | ||
- | coeff[7] = 16'd13200; | ||
- | |||
- | //Initialize delay line. | ||
- | for(i = 0; i < `FILT_LENGTH; i = i+1'b1) begin | ||
- | delay_line[i] = 16'd0; | ||
- | end | ||
- | end | ||
- | | ||
- | //Advance the data through the delay line every clock cycle. | ||
- | generate | ||
- | for (c = `FILT_LENGTH-1; c > 0; c = c - 1) begin: inc_delay | ||
- | always @(posedge clk) begin | ||
- | if(en) delay_line[c] <= delay_line[c-1]; | ||
- | end | ||
- | end | ||
- | endgenerate | ||
- | | ||
- | //Update with input data. | ||
- | always @(posedge clk) begin | ||
- | if(en) delay_line[0] <= din; | ||
- | end | ||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | ##### lfsr.v | ||
- | <code verilog> | ||
- | |||
- | `timescale 1ns / 1ps | ||
- | |||
- | module lfsr( | ||
- | input clk, | ||
- | input en, | ||
- | input rst, | ||
- | output [15:0]lfsr_out | ||
- | ); | ||
- | | ||
- | //Create a 16-bit linear feedback shift register with | ||
- | //maximal polynomial x^16 + x^14 + x^13 + x^11 + 1. | ||
- | reg [15:0]lfsr = 16'd1; | ||
- | wire feedback; | ||
- | | ||
- | assign feedback = ((lfsr[15] ^ lfsr[13]) ^ lfsr[12]) ^ lfsr[10]; | ||
- | assign lfsr_out = lfsr; | ||
- | | ||
- | //Update the linear shift feedback register. | ||
- | always @(posedge clk) begin | ||
- | if(rst) lfsr <= 16'd1; | ||
- | else if(en) lfsr <= {lfsr[14:0], feedback}; | ||
- | end | ||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | ##### BLMS_TB.v | ||
- | <code verilog> | ||
- | |||
- | `timescale 1ns / 1ps | ||
- | |||
- | module BLMS_TB; | ||
- | reg clk = 1'b0; | ||
- | reg [7:0]sw = 8'd0; | ||
- | wire [7:0]JA; | ||
- | | ||
- | wire clk_50MHz; | ||
- | wire clk_25MHz; | ||
- | | ||
- | wire signed [15:0]tone_and_noise; | ||
- | wire signed [15:0]fout; | ||
- | wire signed [15:0]dout0; | ||
- | wire signed [15:0]dout1; | ||
- | wire signed [15:0]dout2; | ||
- | wire signed [15:0]dout3; | ||
- | wire signed [15:0]blms_din0; | ||
- | wire signed [15:0]blms_din1; | ||
- | wire signed [15:0]blms_din2; | ||
- | wire signed [15:0]blms_din3; | ||
- | wire en; | ||
- | | ||
- | BLMS_Top uut(.clk(clk), .sw(sw), .JA(JA)); | ||
- | | ||
- | assign clk_50MHz = uut.clk_50MHz; | ||
- | assign clk_25MHz = uut.clk_25MHz; | ||
- | | ||
- | assign tone_and_noise = uut.tone_and_noise; | ||
- | assign fout = uut.fout; | ||
- | assign dout0 = uut.dout0; | ||
- | assign dout1 = uut.dout1; | ||
- | assign dout2 = uut.dout2; | ||
- | assign dout3 = uut.dout3; | ||
- | assign blms_din0 = uut.blms_din0; | ||
- | assign blms_din1 = uut.blms_din1; | ||
- | assign blms_din2 = uut.blms_din2; | ||
- | assign blms_din3 = uut.blms_din3; | ||
- | assign en = uut.en; | ||
- | | ||
- | //Generate 100MHz clock. | ||
- | always #5 clk = ~clk; | ||
- | | ||
- | initial begin | ||
- | #500000 sw = 8'd1; | ||
- | end | ||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||