前言
在FPGA设计的过程中,有时需要对一些递归的算法进行硬件实现,那么递归调用是否是Verilog所支持的?答案是可以,但是这类算法一般都有比较明确的结构,即递归调用的结构比较清晰明了。那么,我们在RTL代码编写过程中,可以在模块的内部例化当前模块,达到递归调用的目的。
例子
比如,我们设计一个加法器,想要实现如下图的功能,输入N个数据,通过N/2个加法器两两相加,得到N/2个数据,再用N/4个加法器对这N/2个数据进行两两相加,得到N/4个数据…,依此类推,直至计算得到一个数据,即最终计算结果(这里只是用于举例,实际上加法不用这么复杂)。
那么,根据设计要求编写相关代码和测试代码如下。
顶层代码
顶层代码如下:
module test
#(
parameter N = 8,
parameter DW = 8
)
(
clk,
rst_n,
data_in,
data_out
);
input wire clk;
input wire rst_n;
input wire [N*DW-1:0] data_in;
output wire [N*DW-1:0] data_out;
wire [N*DW-1:0] temp;
if(N>2) begin
//1-2-4
test
#(
.N(N/2),
.DW(DW)
)
test_1
(
.clk(clk),
.rst_n(rst_n),
.data_in(data_in[(N/2)*DW-1:0]),
.data_out(temp[(N/2)*DW-1:0])
);
test
#(
.N(N/2),
.DW(DW)
)
test_2
(
.clk(clk),
.rst_n(rst_n),
.data_in(data_in[N*DW-1:(N/2)*DW]),
.data_out(temp[N*DW-1:(N/2)*DW])
);
adder
#(
.N(N),
.DW(DW)
)
adder_inst
(
.clk(clk),
.rst_n(rst_n),
.data_in(temp),
.data_out(data_out)
);
end else if(N == 2) begin
adder
#(
.N(N),
.DW(DW)
)
adder_inst
(
.clk(clk),
.rst_n(rst_n),
.data_in(data_in),
.data_out(data_out)
);
end
endmodule
加法器子模块
加法器子模块的代码如下:
module adder
#(
parameter N = 2,
parameter DW = 8
)
(
clk,
rst_n,
data_in,
data_out
);
input wire clk;
input wire rst_n;
input wire [N*DW-1:0] data_in;
output reg [N*DW-1:0] data_out;
always @(posedge clk or negedge rst_n)
if(!rst_n)
data_out <= 0;
else
data_out[0+:N*DW] <= data_in[(N/2)*DW+:(N/2)*DW] + data_in[0+:(N/2)*DW];
endmodule
Test_Bench
仿真代码如下:
`timescale 1ns/1ns
module tb_test();
parameter N = 8;
parameter DW = 8;
reg clk,rst_n;
reg [N*DW-1:0] data_in;
wire [N*DW-1:0] data_out;
initial
begin
clk = 0;
rst_n = 1'b0;
#20
rst_n = 1'b1;
data_in[7:0] <= 'd1;
data_in[15:8] <= 'd2;
data_in[23:16] <= 'd3;
data_in[31:24] <= 'd4;
data_in[39:32] <= 'd5;
data_in[47:40] <= 'd6;
data_in[55:48] <= 'd7;
data_in[63:56] <= 'd8;
end
always #10 clk = ~clk;
test
#(
.N(N),
.DW(DW)
)
tb_test
(
.clk(clk),
.rst_n(rst_n),
.data_in(data_in),
.data_out(data_out)
);
endmodule
仿真结果
仿真结果如下,可见我们输入了8个数值:1、2、3、4、5、6、7、8,得到8个数相加的结果为36,与实际结果一致,且在这里计算花费了3个时钟周期,与前面图中一致,设置了3级的加法器,即需要3个时钟周期。
RTL视图
RTL视图如下:
总结
递归例化模块本身在Verilog代码编写的过程中是允许的,而且是可综合的,这使得我们在实现一些含明确的递归结构的算法的时候会更加方便,减少代码量。
注:以上仅为个人学习笔记,如有疑问,欢迎评论区探讨交流,如有引用,请备注出处!