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设计思想之“逻辑复制”_加法器_02

可见,占用了两个选择器和一个加法器;

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

下面内容来自于: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语法是设计出好的模型、减少工作量的前提。


最后有关inout端口的处理,给出一篇链接,仅供参考!

verilog 中inout管脚的处理