天天看點

FPGA設計思想之“邏輯複制”

1、邏輯複制是一種通過增加面積來改善時序條件的優化手段,它最主要的應用時調整信号的扇出。如果某個信号需要驅動的後級邏輯信号較多,也就是其扇出非常大,那麼為了增加這個信号的驅動能力,就必須插入很多級的Buffer,這樣就在一定程度上增加了這個信号的路徑延遲。

這種情況下就可以複制生成這個信号的邏輯,用多路同頻同相的信号驅動後續電路,使平均到每路的扇出變低,這樣不需要插入Buffer就能滿足驅動能力增加的要求,進而節省路徑延遲。

舉一個例子:這個例子來自于特權同學《深入淺出玩轉FPGA》

例一:未進行邏輯複制時:

module logic_copy(
input a,b,c,d,
input  sel,
output dout
);

assign dout = sel?(a + b):(c + d);


endmodule
           

對應的RTL原理圖為:

FPGA設計思想之“邏輯複制”

可見,占用了兩個加法器和一個二選一的多路選擇器;

例二:邏輯複制後:

module logic_copy(
input a,b,c,d,
input  sel,
output dout
);
wire ab,cd;
assign ab = sel ? a : c;
assign cd = sel ? b : d;
assign dout = ab + cd;


endmodule
           
FPGA設計思想之“邏輯複制”

可見,占用了兩個選擇器和一個加法器;

2、FPGA中需要做很多重複工作

在某些FPGA設計中,需要很多重複設計的時候,這時候邏輯複制也就有用了。

例如:在某個特殊應用場合需要設計方向可以任意改變的240位寬的三态IO管腳。我們先看看常用的一個位寬的三态管腳怎麼設計。

module inout_interface(
    dat_in,
    io_out,
    io_dir,
    dat_out
    );
    input       dat_in;
    input       io_dir;
    output      dat_out;
    inout       io_out;
    
    assign      io_out  = io_dir ? dat_in : 1'bz;
    assign      dat_out = io_out;
    
endmodule           

如上述程式所示為單個雙向IO口的典型設計代碼,中間由IO輸入方向控制資料和高阻之間的切換,難題出現了,怎麼設計240位寬的雙向IO口呢?難道如下列程式所示:

module inout_interface(
    dat_in,
    io_out,
    io_dir,
    dat_out
    );
    input  [239 : 0]     dat_in;
    input  [239 : 0]     io_dir;
    output [239 : 0]     dat_out;
    inout  [239 : 0]     io_out;
    
    assign      io_out  = io_dir ? dat_in : 240'bz;
    assign      dat_out = io_out;
    
endmodule           

顯然這樣是不行的,因為當io_dir為240位的時候隻有當全為0的時候此式才為假,其餘時候都為真,顯然達不到想要的每個IO都是雙向口的設計。

修改代碼如下:

module inout_interface(

    dat_in,

    io_out,

    io_dir,

    dat_out

    );

    input  [239 : 0]     dat_in;

    input  [239 : 0]     io_dir;

    output [239 : 0]     dat_out;

    inout  [239 : 0]     io_out;

   

    assign      io_out[0]  = io_dir[0] ? dat_in[0] : 1'bz;

    assign      dat_out[0] = io_out[0];

   

    assign      io_out[1]  = io_dir[1] ? dat_in[1] : 1'bz;

    assign      dat_out[1] = io_out[1];

   

    assign      io_out[2]  = io_dir[2] ? dat_in[2] : 1'bz;

    assign      dat_out[2] = io_out[2];

   

    .

    .       // 此處略去1萬行

    .

   

    assign      io_out[239]  = io_dir[239] ? dat_in[239] : 1'bz;

    assign      dat_out[239] = io_out[239];

   

endmodule           

  顯然這種辦法能實作240位寬的獨立方向控制IO,但是估計寫代碼要累死人,有沒得更好的辦法呢?

  當然有,在verilog2001中有個邏輯複制文法——generate,可以對verilog子產品進行無限複制。有了這個子產品我們即可輕松通過邏輯複制來達到我們的要求了。

// 單個雙向IO實作子產品

module  pin_inout(

    indat,

    indir,

    outdat,

    outdatin

    );

   

    input       indat;

    input       indir;

    inout       outdat;

    output      outdatin;

   

    assign      outdat   = indir ? indat : 1'bz;

    assign      outdatin = outdat;

 

endmodule

 

module inout_interface(

    dat_in,

    io_out,

    io_dir,

    dat_out

    );

    input  [239 : 0]     dat_in;

    input  [239 : 0]     io_dir;

    output [239 : 0]     dat_out;

    inout  [239 : 0]     io_out;

   

    // 邏輯複制240次

    genvar  i;

    generate

        for(i = 0; i < 240; i = i + 1)

        begin : pin_loop

            pin_inout   pin_inout_inst(

                .indat          (   dat_in[i]       ),

                .indir          (   io_dir[i]       ),

                .outdat         (   io_out[i]       ),

                .outdatin       (   dat_out[i]      )

            );

        end

    endgenerate

   

endmodule
           

由上面代碼可看出,巧妙利用verilog文法能減少自身工作量。

在FPGA設計中有些情況的邏輯複制不需要我們做,但是有些情況的邏輯複制不得不手工完成,是以,熟練掌握verilog文法是設計出好的模型、減少工作量的前提。