crazybird

【原创】FPGA之资源优化思想的运用

0
阅读(3971)

 很多不安于现状的年轻人心中都有一个明确的目标,并最终为之留下了心酸和泪水而走上了成功的道路。如今我就觉得自己挺年轻的,不过我并没有像他们那么的努力。为了实现梦想,对得起自己,从现在开始我要向他们学习拼搏、执着的精神。哪怕前方的路途再怎么曲折、不平坦,我也要硬着头皮走下去。好了,该回归正题了~~~

   我常常对自己说:“因为我不会,所以要学别人的东西。但是不要只是学习它的内容,而更重要的是它的精髓、灵魂。”接下来,将以复数相乘的事例来说明资源优化的思想。现在给出两个复数Ar+Aij和Br+Bij,他们的乘法可表示为

11

      12

如果按照上述表达式来实现电路的话,它将需要4个乘法器。当然,若以并行结构来实现,将是速度最快的方案,但也是最耗资源的方案。为了优化资源,我们还可以继续将表达式化为  

          13

这样一来,只需要3个乘法器和一些额外的加减运算就可实现复数乘法了。我们这样做的目的是在某些设计中(比如OFDM通信基带的设计中需要许多复数乘法器)可以节省宝贵的专用乘法器资源,有利于改善设计的资源消耗。

   介绍了理论的东西之后,总得将它设计成电路。首先,了解下Quartus II中乘法器IP核的调用,点击菜单“Tool--->MegaWizard Plug-In Manager”,将出现IP核调用向导,如下图所示:

1

选择第一项,创建新的宏功能模块,Next。。

2

(1)选择乘法器IP核;(2)设置器件型号;(3)设置生成文件为Verilog HDL类型;(4)输入文件名和存放的路径。Next。。

3

设置输入数据的位宽,其他选项默认就可以了。Next。。

4

设置乘法器为有符号类型,Next。。

5

设置输入到输出延时一个时钟周期(当然也可以为其他,视情况而定),勾选时钟使能,优化选项默认,Next。。

6

直接Next。。

7

Finish。。将弹出如下对话:

8

在这里选择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

仿真结果如下所示:

14

由仿真时序图可以验证本设计是正确的。第一次用Windows Live Writer的多种技巧,折腾了好久,好困啊,发发就睡了。晚安,88*^_^*