【原创】FPGA之资源优化思想的运用
0赞很多不安于现状的年轻人心中都有一个明确的目标,并最终为之留下了心酸和泪水而走上了成功的道路。如今我就觉得自己挺年轻的,不过我并没有像他们那么的努力。为了实现梦想,对得起自己,从现在开始我要向他们学习拼搏、执着的精神。哪怕前方的路途再怎么曲折、不平坦,我也要硬着头皮走下去。好了,该回归正题了~~~
我常常对自己说:“因为我不会,所以要学别人的东西。但是不要只是学习它的内容,而更重要的是它的精髓、灵魂。”接下来,将以复数相乘的事例来说明资源优化的思想。现在给出两个复数Ar+Aij和Br+Bij,他们的乘法可表示为
即
如果按照上述表达式来实现电路的话,它将需要4个乘法器。当然,若以并行结构来实现,将是速度最快的方案,但也是最耗资源的方案。为了优化资源,我们还可以继续将表达式化为
这样一来,只需要3个乘法器和一些额外的加减运算就可实现复数乘法了。我们这样做的目的是在某些设计中(比如OFDM通信基带的设计中需要许多复数乘法器)可以节省宝贵的专用乘法器资源,有利于改善设计的资源消耗。
介绍了理论的东西之后,总得将它设计成电路。首先,了解下Quartus II中乘法器IP核的调用,点击菜单“Tool--->MegaWizard Plug-In Manager”,将出现IP核调用向导,如下图所示:
选择第一项,创建新的宏功能模块,Next。。
(1)选择乘法器IP核;(2)设置器件型号;(3)设置生成文件为Verilog HDL类型;(4)输入文件名和存放的路径。Next。。
设置输入数据的位宽,其他选项默认就可以了。Next。。
设置乘法器为有符号类型,Next。。
设置输入到输出延时一个时钟周期(当然也可以为其他,视情况而定),勾选时钟使能,优化选项默认,Next。。
直接Next。。
Finish。。将弹出如下对话:
在这里选择Yes。如果选择No,则需要手动添加文件。至此,IP核的调用完毕。
接下来,就可以在设计的源文件中例化该IP核了。为此,我自己写了简单的例程,希望大家可以看得明白。
/******************************************************* Author : crazyBird Filename : Complex_Multiplier.v Data : 2015-3-4 Description : Multiplier of complex data. ********************************************************/ `timescale 1ns/1ps module Complex_Multiplier ( input Clk, //global clock input Rst_n, //global reset input InputEnable, //input enable input [ 7:0] DataInARe, //input data input [ 7:0] DataInAIm, input [ 7:0] DataInBRe, input [ 7:0] DataInBIm, output reg OutputEnable, //output valid output reg [15:0] DataOutRe, //output data output reg [15:0] DataOutIm ); //----------------------------------------- //input buffer reg [7:0] BufferDataARe; reg [7:0] BufferDataAIm; reg [7:0] BufferDataBRe; reg [7:0] BufferDataBIm; reg BufferEnable; always @(posedge Clk or negedge Rst_n) begin if(!Rst_n) begin BufferDataARe <= 8'b0; BufferDataAIm <= 8'b0; BufferDataBRe <= 8'b0; BufferDataBIm <= 8'b0; BufferEnable <= 1'b0; end else begin if(InputEnable) begin BufferDataARe <= DataInARe; BufferDataAIm <= DataInAIm; BufferDataBRe <= DataInBRe; BufferDataBIm <= DataInBIm; BufferEnable <= 1'b1; end else begin BufferDataARe <= 8'b0; BufferDataAIm <= 8'b0; BufferDataBRe <= 8'b0; BufferDataBIm <= 8'b0; BufferEnable <= 1'b0; end end end //------------------------------------------ //compute Ar+Ai,Ar-Ai,Br+Bi reg [8:0] TempSumA; //Ar+Ai reg [8:0] TempDifferenceA; //Ar-Ai reg [8:0] TempSumB; //Br+Bi reg [7:0] TempARe; //Ar reg [7:0] TempBRe; //Br reg [7:0] TempBIm; //Bi reg Temp_En; always @(posedge Clk or negedge Rst_n) begin if(!Rst_n) begin Temp_En <= 1'b0; TempSumA <= 9'b0; //Ar+Ai TempDifferenceA <= 9'b0; //Ar-Ai TempSumB <= 9'b0; //Br+Bi TempARe <= 8'b0; TempBRe <= 8'b0; TempBIm <= 8'b0; end else begin if(BufferEnable) begin Temp_En <= 1'b1; TempSumA <= {BufferDataARe[7],BufferDataARe} + {BufferDataAIm[7],BufferDataAIm}; //signal data add TempDifferenceA <= {BufferDataARe[7],BufferDataARe} - {BufferDataAIm[7],BufferDataAIm}; //signal data sub TempSumB <= {BufferDataBRe[7],BufferDataBRe} + {BufferDataBIm[7],BufferDataBIm}; TempARe <= BufferDataARe; TempBRe <= BufferDataBRe; TempBIm <= BufferDataBIm; end else begin Temp_En <= 1'b0; TempSumA <= 9'b0; TempDifferenceA <= 9'b0; TempSumB <= 9'b0; TempARe <= 8'b0; TempBRe <= 8'b0; TempBIm <= 8'b0; end end end //------------------------------------------- //instance of IP core wire [16:0] SumA_mult_Bi; wire [16:0] DifferenceA_mult_Br; wire [16:0] SumB_mult_Ar; //compute Bi*(Ar+Ai) width9_multiply_width8 SumAmultiplyBr ( .clock (Clk ), .dataa (TempSumA ), .datab (TempBIm ), .clken (Temp_En ), .result(SumA_mult_Bi) ); //compute Ar*(Br+Bi) width9_multiply_width8 SumBmultiplyAr ( .clock (Clk ), .dataa (TempSumB ), .datab (TempARe ), .clken (Temp_En ), .result(SumB_mult_Ar) ); //compute Br*(Ar-Ai) width9_multiply_width8 DifferenceAmultiplyBi ( .clock (Clk ), .dataa (TempDifferenceA ), .datab (TempBRe ), .clken (Temp_En ), .result(DifferenceA_mult_Br) ); //------------------------------------------ //valid data output flag reg rdy; always @(posedge Clk or negedge Rst_n) begin if(!Rst_n) rdy <= 1'b0; else rdy <= Temp_En; end //------------------------------------------ //compute Ar*(Br+Bi)- Br*(Ar-Ai) and Ar*(Br+Bi)- Bi*(Ar+Ai) reg [17:0] TempRe; reg [17:0] TempIm; reg TempEnable; always @(posedge Clk or negedge Rst_n) begin if(!Rst_n) begin TempRe <= 18'b0; TempIm <= 18'b0; TempEnable <= 1'b0; end else begin if(rdy) begin TempRe <= {SumB_mult_Ar[16],SumB_mult_Ar}-{SumA_mult_Bi[16],SumA_mult_Bi}; //signal data sub TempIm <= {SumB_mult_Ar[16],SumB_mult_Ar}-{DifferenceA_mult_Br[16],DifferenceA_mult_Br}; TempEnable <= 1'b1; end else begin TempRe <= 18'b0; TempIm <= 18'b0; TempEnable <= 1'b0; end end end //----------------------------------------------------------------------------- //output data always @(posedge Clk or negedge Rst_n) begin if(!Rst_n) begin DataOutRe <= 16'b0; DataOutIm <= 16'b0; OutputEnable <= 1'b0; end else begin if(TempEnable) begin DataOutRe <= {TempRe[17],TempRe[14:0]}; DataOutIm <= {TempIm[17],TempIm[14:0]}; OutputEnable <= 1'b1; end else begin DataOutRe <= 16'b0; DataOutIm <= 16'b0; OutputEnable <= 1'b0; end end end endmodule
测试代码如下:
/******************************************************* Author : crazybird Filename : Complex_Multiplier_tb.v Data : 2015-3-4 Description : Simulation of Complex_Multiplier. ********************************************************/ `timescale 1ns/1ps module Complex_Multiplier_tb; reg Clk; reg Rst_n; reg InputEnable; reg [ 7:0] DataInARe; reg [ 7:0] DataInAIm; reg [ 7:0] DataInBRe; reg [ 7:0] DataInBIm; wire OutputEnable; wire [15:0] DataOutRe; wire [15:0] DataOutIm; Complex_Multiplier u_Complex_Multiplier ( .Clk (Clk ), .Rst_n (Rst_n ), .InputEnable (InputEnable ), .DataInARe (DataInARe ), .DataInAIm (DataInAIm ), .DataInBRe (DataInBRe ), .DataInBIm (DataInBIm ), .OutputEnable(OutputEnable), .DataOutRe (DataOutRe ), .DataOutIm (DataOutIm ) ); //------------------------------------- //clock generate module localparam PERIOD = 20; //50MHz initial begin Clk = 0; forever #(PERIOD/2) Clk = ~Clk; end task task_reset; begin Rst_n = 0; repeat(2) @(negedge Clk); Rst_n = 1; end endtask //---------------------------------------- //testbench of the RTL initial begin task_reset; @(negedge Clk); InputEnable = 1'b1; DataInARe = 8'b1010_1010; DataInAIm = 8'b0101_0101; DataInBRe = 8'b1111_0000; DataInBIm = 8'b0000_1111; @(negedge Clk); InputEnable = 1'b0; DataInARe = 8'b0; DataInAIm = 8'b0; DataInBRe = 8'b0; DataInBIm = 8'b0; repeat(10)@(negedge Clk); InputEnable = 1'b1; DataInARe = 8'b1011_1110; DataInAIm = 8'b1101_0001; DataInBRe = 8'b1000_0110; DataInBIm = 8'b0100_1001; @(negedge Clk); InputEnable = 1'b0; DataInARe = 8'b0; DataInAIm = 8'b0; DataInBRe = 8'b0; DataInBIm = 8'b0; end endmodule
仿真结果如下所示:
由仿真时序图可以验证本设计是正确的。第一次用Windows Live Writer的多种技巧,折腾了好久,好困啊,发发就睡了。晚安,88*^_^*