同时,对比程序运行结果和MATLAB的计算结果(如章节开头表格所示),可知,二者结果是一致的,其中个别数据的小误差是由于移位取代小数乘法运算带来的误差。因此,程序设计是正确的。 于是,根据以上所有思想我们可以得出以下11阶FIR数字滤波器的Verilog程序如下: /////////////////////////////////////////////////////////////////////////////// // Company: // Engineer:
// Create Date: 17:01:38 11/03/06 // Design Name: // Module Name: ycj // Project Name: // Target Device: // Tool versions:
// Description:用Verilog编写的fir滤波器程序 // Dependencies: // Revision:
// Revision 0.01 - File Created // Additional Comments:
//////////////////////////////////////////////////////////////// module firv2(clk, x, y); input clk; input [7:0] x; output [25:0] y; reg [26:0] y;
reg[7:0] x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16; wire[21:0] acc1,acc2,acc3,acc4,acc5,acc6,acc7,acc8,acc9,acc10,acc11,acc12,acc13,acc14,acc15,acc16,acc17; reg [8:0]sxin[0:32]; reg [5:0]i,k; reg [8:0]xx[16:0]; parameter c0=-21, c1=-8, c2= 22, c3=34, c4=6,
20
c5=-34, c6=-31, c7=32, c8=87, c9=32, c10=-154, c11=-321, c12=-217, c13=321, c14=1185, c15=1996, c16=2328; always @ (posedge clk) begin
xx[16]<=sxin[16] ; for(i=0;i<16;i=i+1) xx[i]<=sxin[i]+sxin[32-i] ; for(k=32;k>0;k=k-1) sxin[k]<=sxin[k-1]; sxin[0]<={x[7],x}; end
mult13_8 uut0(clk,c0,xx[0],acc1); mult13_8 uut1(clk,c1,xx[1],acc2); mult13_8 uut2(clk,c2,xx[2],acc3); mult13_8 uut3(clk,c3,xx[3],acc4); mult13_8 uut4(clk,c4,xx[4],acc5); mult13_8 uut5(clk,c5,xx[5],acc6); mult13_8 uut6(clk,c6,xx[6],acc7); mult13_8 uut7(clk,c7,xx[7],acc8); mult13_8 uut8(clk,c8,xx[8],acc9); mult13_8 uut9(clk,c9,xx[9],acc10); mult13_8 uut10(clk,c10,xx[10],acc11); mult13_8 uut11(clk,c11,xx[11],acc12); mult13_8 uut12(clk,c12,xx[12],acc13);
21
mult13_8 uut13(clk,c13,xx[13],acc14); mult13_8 uut14(clk,c14,xx[14],acc15); mult13_8 uut15(clk,c15,xx[15],acc16); mult13_8 uut16(clk,c16,xx[16],acc17); always @(posedge clk) begin
y<={acc16[1],acc16[1],acc16[1],acc16[1],acc16[1],acc16}+{acc17[1],acc17[1],acc17[1],acc17[1],acc17[1],acc17}
+{acc15[1],acc15[1],acc15[1],acc15[1],acc15[1],acc15}+{acc14[1],acc14[1],acc14[1],acc14[1],acc14[1],acc14}
+{acc13[1],acc13[1],acc13[1],acc13[1],acc13[1],acc13}+{acc12[1],acc12[1],acc12[1],acc12[1],acc12[1],acc12}
+{acc11[1],acc11[1],acc11[1],acc11[1],acc11[1],acc11}+{acc10[1],acc10[1],acc10[1],acc10[1],acc10[1],acc10}
+{acc9[1],acc9[1],acc9[1],acc9[1],acc9[1],acc9}+{acc8[1],acc8[1],acc8[1],acc8[1],acc8[1],acc8}
+{acc7[1],acc7[1],acc7[1],acc7[1],acc7[1],acc7}+{acc6[1],acc6[1],acc6[1],acc6[1],acc6[1],acc6}
+{acc5[1],acc5[1],acc5[1],acc5[1],acc5[1],acc5}+{acc4[1],acc4[1],acc4[1],acc4[1],acc4[1],acc4}
+{acc3[1],acc3[1],acc3[1],acc3[1],acc3[1],acc3}+{acc2[1],acc2[1],acc2[1],acc2[1],acc2[1],acc2}
+{acc1[1],acc1[1],acc1[1],acc1[1],acc1[1],acc1}; end endmodule 1.分析程序设计
使用MAC单元完成乘加运算(包括单MAC和多MAC的情况)这个方法可以利用FPGA中已有的MAC单元(像Xilinx Spartan 3E-100中有四个乘加单元),只要设计好数据运算流程,就能方便高效地实现FIR运算。使用MAC单元还有一个优点是系数可以存成系数表,可以方便地修改,这是移位方法代替乘法运算所不及的。
使用移位代替乘法运算这个方法的优点是速度快,例如11阶的滤波器,完成一次运算需要11次乘法,如果使用单MAC的话,需要11个时钟周期来完成,而使用移位方法可以在一个时钟周期完成11个乘法运算;缺点是需要另外去完成滤波系数到移位位数的换算,如果修改滤波系数的话,程序修改将会比较麻烦,同时硬件资源也要使用多一些。
22
t*0.125={t[7],t[7],t[7],t[7:3]} t*0.125 = t/8 = t>>3;
t为有符号数,所以是带符号右移,于是t>>3 ={t[7],t[7],t[7],t[7:3]} 之所以这么些就是为了节省资源,提高频率 以 -4*0.5 为例
-4的原码:1000 0100B 补码:1111 1100B -4>>1=0111 1110
而符号位不能变 应用原来的位代替 1111 1110B 的原码 1000 0010B =-2 2. 对程序设计中的问题分析与总结
在最开始的设计中,本文初始计划使用乘法单元。但是在程序设计的过程中我们遇见了实数乘法的问题,程序的运行遇到了困难,在与指导老师的研究中我们发现问题出在实数乘法的问题上。在Verilog的运算中实数乘法需要特殊的小数乘法器来单元来实现。在原来的38阶滤波器的设计中出现了这样子的问题。我们使用过这样的程序: reg [63:0] filter_in_force [0:3344]; reg [63:0] filter_out_expected [0:3344]; // Function definitions function real abs_real; input real arg; begin
abs_real = arg > 0 ? arg : -arg; end
endfunction //function abs_real // Component Instances filter u_filter ( .clk(clk),
.clk_enable(clk_enable), .reset(reset), .filter_in(filter_in), .filter_out(filter_out) ); initial begin
23
// Constants
filter_in_force [0] <= $realtobits(1.0000000000000000E+000); filter_in_force [1] <= $realtobits(0.0000000000000000E+000); filter_in_force [2] <= $realtobits(0.0000000000000000E+000);
filter_in_force [3] <= $realtobits(0.0000000000000000E+000); …
系统无法实现real值得计算,于是这里需要我们用小数乘法器进行特殊单元的方案解决。于是我们要进行小数乘法器的设计。 3.小数乘法器介绍及在设计中的作用
随着FPGA 的发展以及相应EDA 软件工具的成熟,FPGA 在高速数字信号处理领域得到了越来越广泛的应用。而乘法,尤其是浮点乘法运算是数值计算和数据分析中最常用的运算之一。目前,多数FPGA 上可以实现整数和标准逻辑矢量的乘法,但不支持浮点乘法运算, 因此使得FPGA 在数值计算、数据分析和信号处理等方面受到了限制。本文采用适合于FPGA 实现的自定义26 位浮点数据格式,利用改进的基4Boot h 编码运算方式,以及CSA和4 - 2 压缩器综合的Wallace 树形结构,减少了部分积,使系统具有高速度,低功耗的特点,并且结构规则。在尾数的舍入中采用了基于预测和选择的舍入方法,进一步提高了运算的速度,优化了乘法器的性能。 4.小数乘法器程序设计与仿真
modulefix_mult ( clk,rst_n,in_a,in_b,x1,x2,x3,x4,x5,x6,x7,y_out );
inputclk,rst_n;//时钟和复位信号
input[31:0] in_a,in_b;//输入的被乘数和乘数 output[31:0] y_out;//输出的乘积
/*寄存器类型变量 为了能更清楚的了解全处理过程, 特地设计为输出的,不然仿真可能会被综合掉*/ output[15:0] x1,x2,x3,x4; output[0:0] x5; output[29:0] x6; output[31:0] x7;
///////////////////////////////////////////////////// reg[31:0] y_out;
reg[15:0] x1,x2,x3,x4; reg[0:0] x5; reg[29:0] x6; reg[31:0] x7;
24