本章讨论关于数字设计中的“面积”问题,并提出若干在FPGA设计中优化面积的方法。
我们将通过选择不同拓扑结构来减少面积消耗,这与我们熟知的通过综合、布线工具的约束来优化电路面积不同,约束方式是针对不同器件特性来降低逻辑门与模块的数量,而拓扑结构是在更高层面上来解决这个问题,适用于所有器件。
优化面积通常是最大限度地重用逻辑资源,这会以牺牲数据吞吐量为代价。
本章将具体针对下列问题进行讨论:
1)收起流水线以在不同计算阶段重用逻辑资源。
2)在无现有的递归、循环等算法时,通过控制逻辑来实现逻辑复用。
3)在不同功能操作之间共享逻辑资源。
4)复位对面积优化的影响:
- 缺少reset功能的影响;
- 缺少set功能的影响;
- 缺少异步reset功能的影响;
- RAM reset的影响;
- 使用set/reset对逻辑资源进行优化。
2.1 收起流水线
顾名思义,本小节与上一章的流水线操作正相反,通过复用流水线中的重复逻辑,实现面积的降低。
定点数乘法是常见的可以写为流水线的设计模块,我们可以通过添加移位和加法器来“收起”它,乘法器被优化为受B位数控制的A的移位累加算法。
优化前代码:
module mult8(
output [7:0] product,
input [7:0] A,
input [7:0] B,
input clk);
reg [15:0] prod16;
assign product = prod16[15:8];
always @(posedge clk)
prod16 <= A * B;
endmodule
优化后代码:
module mult8(
output done,
output reg [7:0] product,
input [7:0] A,
input [7:0] B,
input clk,
input start);
reg [4:0] multcounter; // counter for number of shift/adds
reg [7:0] shiftB; // shift register for B
reg [7:0] shiftA; // shift register for A
wire adden; // enable addition
assign adden = shiftB[7] & !done;
assign done = multcounter[3];
always @(posedge clk) begin
// increment multiply counter for shift/add ops
if(start) multcounter <= 0;
else if(!done) multcounter <= multcounter + 1;
// shift register for B
if(start) shiftB <= B;
else shiftB[7:0] <= {shiftB[6:0], 1’b0};
// shift register for A
if(start) shiftA <= A;
else shiftA[7:0] <= {shiftA[7], shiftA[7:1]};
// calculate multiplication
if(start) product <= 0;
else if(adden) product <= product + shiftA;
end
endmodule
2.2 基于控制信号的逻辑复用
当共享逻辑明显大于所需的控制逻辑时,可以通过添加控制逻辑的方式实现共享逻辑复用。
多数情况下,逻辑的复用并不想2.1节那么简单,需要创建一些控制逻辑,比如状态机,来更好的实现。以低通FIR滤波器的实现为例。
实现代码:
module lowpassfir(
output reg [7:0] filtout,
output reg done,
input clk,
input [7:0] datain, // X[0]
input datavalid, // X[0] is valid
input [7:0] coeffA, coeffB; coeffC); // coeffs for low pass filter
// define input/output samples
reg [7:0] X0, X1, X2;
reg multdonedelay;
reg multstart; // signal to multiplier to begin computation
reg [7:0] multdat;
reg [7:0] multcoeff; // the registers that are multiplied together
reg [2:0] state; // holds state for sequencing through mults
reg [7:0] accum; // accumulates multiplier products
reg clearaccum; // sets accum to zero
reg [7:0] accumsum;
wire multdone; // multiplier has completed
wire [7:0] multout; // multiplier product
// shift-add multiplier for sample-coeff mults
mult8�8 mult8�8(.clk(clk),
.dat1(multdat),
.dat2(multcoeff),
.start(multstart),
.done(multdone),
.multout(multout));
always @(posedge clk) begin
multdonedelay <= multdone;
// accumulates sample-coeff products
accumsum <= accum + multout[7:0];
// clearing and loading accumulator
if(clearaccum) accum <= 0;
else if(multdonedelay) accum <= accumsum;
// do not process state machine if multiply is not done
case(state)
0: begin
// idle state
if(datavalid) begin
// if a new sample has arrived
// shift samples
X0 <= datain;
X1 <= X0;
X2 <= X1;
multdat <= datain;
multcoeff <= coeffA;
multstart <= 1;
clearaccum <= 1; // clear accum
state <= 1;
end
else begin
multstart <= 0;
clearaccum <= 0;
done <= 0;
end
end
1: begin
if(multdonedelay) begin
// A*X[0] is done, load B*X[1]
multdat <= X1;
multcoeff <= coeffB;
multstart <= 1;
state <= 2;
end
else begin
multstart <= 0;
clearaccum <= 0;
done <= 0;
end
end
2: begin
if(multdonedelay) begin
// B*X[1] is done, load C*X[2]
multdat <= X2;
multcoeff <= coeffC;
multstart <= 1;
state <= 3;
end
else begin
multstart <= 0;
clearaccum <= 0;
done <= 0;
end
end
3: begin
if(multdonedelay) begin
// C*X[2] is done, load output
filtout <= accumsum;
done <= 1;
state <= 0;
end
else begin
multstart <= 0;
clearaccum <= 0;
done <= 0;
end
end
default
state <= 0;
endcase
end
endmodule
2.3 逻辑共享
对于以面积为主要要求的紧凑型设计,应在不同模块中搜索相似的逻辑,这些逻辑可以被带到全局层面被多个模块共享。
下图中模块A和B是两个完全独立的逻辑。A是一个计数分频器,8-bit计数器自动计数和归零;B是一个PWM生成器,11-bit计数器在固定值归零。通过逻辑共享,可以有效节省面积。
优化前:
优化后:
2.4 复位对面积的影响
不恰当的复位方式可能造成大量额外的逻辑资源浪费,不利于面积优化。
2.4.1 reset对资源的影响
FPGA内部有许多特定的built-in资源,例如移位寄存器,可以有效节省LUT与FF的使用,但是在非必要的reset使用情况下,综合工具就会放弃使用built-in资源,造成资源浪费。如下两种设计会导致完全不同的结果:
生成的电路区别如下:
2.4.2 set对资源的影响
与移位寄存器不同,大多数FPGA的内置DSP资源包含reset功能,但如何非要使用set,则会在输出端的产生多余逻辑。
2.4.3 异步reset对资源的影响
许多新出的高性能FPGA内置资源还有同步reset功能,如DSP,但如果非要使用异步reset,也会浪费大量逻辑资源。
2.4.4 reset RAM
去复位RAM通常是一种糟糕的设计,尤其是使用异步复位。
通常情况下,我们希望使用BRAM资源来完成FPGA内部存储功能,节省FF资源,但不恰当的复位(异步复位)会适得其反。
2.4.5 利用FF的set/reset因脚来优化设计
可以发现,FF的set可以完成外部或门功能;reset则与外部的与门功能等效。如下图所示:
利用这个原理可以使一些看似复杂的逻辑变得意外简单: