【原创】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*^_^*












