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原理圖為:
可見,占用了兩個加法器和一個二選一的多路選擇器;
例二:邏輯複制後:
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
可見,占用了兩個選擇器和一個加法器;
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文法是設計出好的模型、減少工作量的前提。