FPGA设计中的递归调用(实现递归算法)

FPGA设计中的递归调用(实现递归算法)

前言

  在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代码编写的过程中是允许的,而且是可综合的,这使得我们在实现一些含明确的递归结构的算法的时候会更加方便,减少代码量。

注:以上仅为个人学习笔记,如有疑问,欢迎评论区探讨交流,如有引用,请备注出处!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值