电子说
已知一个加法器IP,其功能是计算两个数的和,但这个和延迟两个周期才会输出。现在有一串连续的数据输入,每个周期都不间断,试问最少需要例化几个上述的加法器IP,才可以实现累加的功能。
实现累加器的加法器例化的个数。按照原文大佬的设计方法,因为数据连续且加法器的延迟周期是2,使用使用一个实现累加,会有一半的数据丢失。那这样设计他就将奇数偶数的数据进行了分开做一级累加,然后第二级将奇数偶数的累加结果再累加。这样做共需消耗3个加法器。
这样设计当然没问题,但是这样设计是否是最少呢?我先抛出我的思考,我认为在允许少量逻辑设计的情况下,最少需要例化两个上述的加法器IP可以实现累加。
如果比较极限的情况下,一个都可以,先把一串数据使用寄存器缓存,然后一个一个取出来慢慢算即可,但这样是不太可取的,首先,数据是连续的并没有给出数据的极限长度,也就是说不论用任何涉及存储结构进行缓存,都没法确保该次数据能完全被存储。如果题目改成一串连续数据输入,长度最大为10,那我认为用寄存器缓存这样的设计是合理的。
回到设计思路:用两个加法器的结构如图示。
假设两个时钟周期延时加法器代码如下,通过例化加法器进行构建累加器。
//加法器IP
module adder
#(parameter DATA_WIDTH = 8)(
input clk,
input rst_n,
input [DATA_WIDTH-1:0] a_in,
input [DATA_WIDTH-1:0] b_in,
output reg [DATA_WIDTH-1:0] out
);
reg [DATA_WIDTH-1:0] sum;
always @(posedge clk or negedge rst_n)begin
if(rst_n == 'd0)begin
sum <= 'd0;
out <= 'd0;
end
else begin
sum <= a_in + b_in;
out <= sum;
end
end
endmodule
//累加器实现
module adder_for_acc
#(parameter DATA_WIDTH = 8)
(
input clk,
input rst_n,
input [DATA_WIDTH-1:0] din,
input din_valid,
output reg dout_valid,
output reg [DATA_WIDTH-1:0] dout
);
reg [DATA_WIDTH-1:0]din_r0;
//打一拍
always @(posedge clk or negedge rst_n)begin
if(rst_n == 'd0)begin
din_r0 <= 'd0;
end
else if(din_valid==1'B1)begin
din_r0<= din;
end
else begin
din_r0<='d0;
end
end
//adder0_valid信号
reg adder0_valid;
always @(posedge clk or negedge rst_n)begin
if(rst_n == 'd0)begin
adder0_valid <= 'd0;
end
else if(din_valid==1'B1)begin
adder0_valid<=!adder0_valid;
end
else begin
adder0_valid<='d0;
end
end
wire[DATA_WIDTH-1:0] a_in = (adder0_valid && din_valid)?din:0;
wire[DATA_WIDTH-1:0] b_in = (adder0_valid)?din_r0:0;
wire[DATA_WIDTH-1:0] ab_sum;
adder adder0_dut (
.clk (clk ),
.rst_n(rst_n ),
.a_in (a_in ),
.b_in (b_in ),
.out (ab_sum)
);
//第一级加法器输出有效信号
reg [1:0]adder0_valid_dly;
wire ab_sum_valid = adder0_valid_dly[1];
always @(posedge clk ) begin
adder0_valid_dly<={adder0_valid_dly[0],adder0_valid};
end
wire [DATA_WIDTH-1:0] sum_in;
wire [DATA_WIDTH-1:0] ab_sum_in = (ab_sum_valid)?ab_sum:0;
wire [DATA_WIDTH-1:0] accsum_in = (ab_sum_valid)?sum_in:dout;
adder adder1_dut (
.clk (clk ),
.rst_n(rst_n ),
.a_in (ab_sum_in),
.b_in (accsum_in),
.out (sum_in )
);
//第二级加法器输出有效信号
reg [3:0]din_valid_r0;
reg [1:0]adder1_valid_dly;
wire adder1_outvld = adder1_valid_dly[1];
always @(posedge clk ) begin
adder1_valid_dly<={adder1_valid_dly[0],ab_sum_valid};
end
//输出
always @(posedge clk ) begin
din_valid_r0<={din_valid_r0[2:0],(din_valid || adder0_valid)};
end
always @(posedge clk or negedge rst_n) begin
if(rst_n == 'd0)begin
dout <= 'd0;
dout_valid <= 'd0;
end
else if(adder1_outvld == 1 && (din_valid_r0[3]==1 && din_valid_r0[2]==0))begin
dout <= sum_in ;
dout_valid <= 'd1;
end
else begin
dout <= dout ;
dout_valid <= 'd0;
end
end
endmodule