FPGA设计篇之冒泡排序

一、写在前面

  在前面,我们分别学习了并行全排序算法和双调排序算法的原理及其RTL代码的编写,在本文中我们将继续学习经典的排序算法——冒泡排序算法,学习其原理及其Verilog实现。

二、冒泡排序原理

  冒泡排序算法Bubble Sort)是一种简单的排序算法,它会逐个元素地重复遍历输入列表,将当前元素与后面的元素进行比较,并根据升序排序或者降序排序交换它们的值。从前往后或者从后往前重复遍历这个列表,直到在一次遍历期间不必执行任何交换,这意味着列表已完全排序。一个长度为N的序列,对该列表的遍历次数为N-1次。那么,具体步骤可以分为以下几个步骤:
  (1)对一个序列中的数值从前往后依次比较相邻的两个数值,如果前面的数值(数值一)大于后面的数值(数值二),则交换这两个数值;
  (2)重复步骤(1)的操作(N-1)次,排序完成;
  那么,对于一个长度N=5的序列,其排序过程如下图所示。

在这里插入图片描述

三、冒泡排序RTL实现

  那么,根据冒泡排序的原理,我们可以编写对于的Verilog代码,如下。对于一个长度为N的序列,每轮排序总共需要进行(N-1)次比较,而总共要进行(N-1)轮的排序,所以在代码中我们分别设置了单论排序计数器cnt_1和排序轮数计数器cnt_2用于计数,如果单轮排序计数器cnt_1达到N-2,则表示单轮排序结束,开始下一轮的排序,如果排序轮数计数器cnt_2达到N-2,则表示对该序列排序结束,输出排序后的数值和标签。另外,我们可以修改参数值ASCEND,设置对序列进行升序排序还是降序排序。

module bubble_sort
#(
	parameter	DATA_WIDTH = 8,
	parameter	LABEL_WIDTH = 8,
	parameter	DATA_NUMBER = 8,
	parameter	ASCEND = 1
)
(
	clk,
	rst_n,
	start,
	data_unsort,
	label_unsort,
	
	data_sorted,
	label_sorted,
	data_valid
);

input	clk;
input	rst_n;
input	start;
input	[DATA_NUMBER*DATA_WIDTH-1:0]	data_unsort; //未排序数值
input	[DATA_NUMBER*LABEL_WIDTH-1:0]	label_unsort; //未排序标签

output	reg	[DATA_NUMBER*DATA_WIDTH-1:0]	data_sorted; //排序后数值
output	reg	[DATA_NUMBER*LABEL_WIDTH-1:0]	label_sorted; //排序后标签
output	reg									data_valid; //数据输出有效标志

reg		[DATA_NUMBER*DATA_WIDTH-1:0]	data_temp;
reg		[DATA_NUMBER*LABEL_WIDTH-1:0]	label_temp;
reg		[2:0]							FSM_state; //排序状态机
reg		[$clog2(DATA_NUMBER)-1:0]		cnt_1; //单轮排序次数计数器
reg		[$clog2(DATA_NUMBER)-1:0]		cnt_2; //排序轮数计数器

localparam Initial = 3'b001; //初始化
localparam Sort	   = 3'b010; //排序
localparam Finish  = 3'b100; //排序结束

// 状态机
always @(posedge clk or negedge rst_n)
  if(!rst_n)
	FSM_state <= Initial;
  else begin
	case(FSM_state)
	  Initial:
		begin
		  if(start)
			FSM_state <= Sort;
		  else
			FSM_state <= Initial;
		end
	
	  Sort:
		begin
		  if(cnt_2 == DATA_NUMBER-2)
			FSM_state <= Finish;
		  else
			FSM_state <= Sort;
		end
		
	  Finish:
		begin
		  FSM_state <= Initial;
		end
	  
	  default:
		FSM_state <= Initial;
	endcase
  end
  
// 单轮排序次数计数器  
always @(posedge clk or negedge rst_n)
  if(!rst_n)
	cnt_1 <= 0;
  else if(FSM_state == Sort && cnt_1 == DATA_NUMBER-2)
	cnt_1 <= 0;
  else if(FSM_state == Sort)
	cnt_1 <= cnt_1 + 1'b1;
  else
	cnt_1 <= 0;

// 排序轮数计数器
always @(posedge clk or negedge rst_n)
  if(!rst_n)
	cnt_2 <= 0;
  else if(FSM_state == Sort && cnt_1 == DATA_NUMBER-2)
	cnt_2 <= cnt_2 + 1'b1;
  else if(FSM_state == Sort)
	cnt_2 <= cnt_2;
  else
	cnt_2 <= 0;

// 排序数值与标签
always @(posedge clk or negedge rst_n)
  if(!rst_n) begin
	data_temp <= 0;
	label_temp <= 0;
  end else if(FSM_state == Initial) begin
	data_temp <= data_unsort;
	label_temp <= label_unsort;
  end else if(FSM_state == Sort) begin
	if(ASCEND == 1'b1) //升序排序
	  if(data_temp[cnt_1*DATA_WIDTH+:DATA_WIDTH] > data_temp[(cnt_1+1)*DATA_WIDTH+:DATA_WIDTH]) begin
	    data_temp[cnt_1*DATA_WIDTH+:DATA_WIDTH] <= data_temp[(cnt_1+1)*DATA_WIDTH+:DATA_WIDTH];
	    data_temp[(cnt_1+1)*DATA_WIDTH+:DATA_WIDTH] <= data_temp[cnt_1*DATA_WIDTH+:DATA_WIDTH];
	    label_temp[cnt_1*LABEL_WIDTH+:LABEL_WIDTH] <= label_temp[(cnt_1+1)*LABEL_WIDTH+:LABEL_WIDTH];
	    label_temp[(cnt_1+1)*LABEL_WIDTH+:LABEL_WIDTH] <= label_temp[cnt_1*LABEL_WIDTH+:LABEL_WIDTH];
	  end else begin 
	    data_temp[cnt_1*DATA_WIDTH+:DATA_WIDTH] <= data_temp[cnt_1*DATA_WIDTH+:DATA_WIDTH];
	    data_temp[(cnt_1+1)*DATA_WIDTH+:DATA_WIDTH] <= data_temp[(cnt_1+1)*DATA_WIDTH+:DATA_WIDTH];
	    label_temp[cnt_1*LABEL_WIDTH+:LABEL_WIDTH] <= label_temp[cnt_1*LABEL_WIDTH+:LABEL_WIDTH];
	    label_temp[(cnt_1+1)*LABEL_WIDTH+:LABEL_WIDTH] <= label_temp[(cnt_1+1)*LABEL_WIDTH+:LABEL_WIDTH];
	  end
	else if(ASCEND == 1'b0) //降序排序
	  if(data_temp[cnt_1*DATA_WIDTH+:DATA_WIDTH] < data_temp[(cnt_1+1)*DATA_WIDTH+:DATA_WIDTH]) begin
	    data_temp[cnt_1*DATA_WIDTH+:DATA_WIDTH] <= data_temp[(cnt_1+1)*DATA_WIDTH+:DATA_WIDTH];
	    data_temp[(cnt_1+1)*DATA_WIDTH+:DATA_WIDTH] <= data_temp[cnt_1*DATA_WIDTH+:DATA_WIDTH];
	    label_temp[cnt_1*LABEL_WIDTH+:LABEL_WIDTH] <= label_temp[(cnt_1+1)*LABEL_WIDTH+:LABEL_WIDTH];
	    label_temp[(cnt_1+1)*LABEL_WIDTH+:LABEL_WIDTH] <= label_temp[cnt_1*LABEL_WIDTH+:LABEL_WIDTH];
	  end else begin
	    data_temp[cnt_1*DATA_WIDTH+:DATA_WIDTH] <= data_temp[cnt_1*DATA_WIDTH+:DATA_WIDTH];
	    data_temp[(cnt_1+1)*DATA_WIDTH+:DATA_WIDTH] <= data_temp[(cnt_1+1)*DATA_WIDTH+:DATA_WIDTH];
	    label_temp[cnt_1*LABEL_WIDTH+:LABEL_WIDTH] <= label_temp[cnt_1*LABEL_WIDTH+:LABEL_WIDTH];
	    label_temp[(cnt_1+1)*LABEL_WIDTH+:LABEL_WIDTH] <= label_temp[(cnt_1+1)*LABEL_WIDTH+:LABEL_WIDTH];
	  end
  end else begin
	data_temp <= data_temp;
	label_temp <= label_temp;
  end

// 数据输出有效标志
always @(posedge clk or negedge rst_n)
  if(!rst_n)
	data_valid <= 1'b0;
  else if(FSM_state == Finish)
	data_valid <= 1'b1;
  else
	data_valid <= 1'b0;

// 排序后数据和标签
always @(posedge clk or negedge rst_n)
  if(!rst_n) begin
	data_sorted <= 0;
	label_sorted <= 0;
  end else if(data_valid)begin
	data_sorted <= data_temp;
	label_sorted <= label_temp;
  end else begin
	data_sorted <= data_sorted;
	label_sorted <= label_sorted;
  end

endmodule

四、TestBench

  在这里,我们以序列长度N=8为例,编写一个简单的测试文件,如下。输入序列为:9,3,15,10,11,8,4,5,其对应的标签为:0,1,2,3,4,5,6,7。那么,经过排序后的数值顺序应当是:3,4,5,8,9,10,11,15,排序后的标签应当是:1,6,7,5,0,3,4,2。

`timescale 1ns/1ns
module tb_bubble_sort();

parameter	DATA_WIDTH = 8;
parameter	DATA_NUMBER = 8;
parameter	LABEL_WIDTH	= $clog2(DATA_NUMBER);
parameter	ASCEND = 1'b1;	

reg clk,rst_n,start;
reg		[DATA_WIDTH-1:0]	data_unsort		[DATA_NUMBER-1:0];
reg		[LABEL_WIDTH-1:0]	label_unsort	[DATA_NUMBER-1:0];

wire	[DATA_WIDTH-1:0]	data_sorted		[DATA_NUMBER-1:0];
wire	[LABEL_WIDTH-1:0]	label_sorted	[DATA_NUMBER-1:0];
wire						data_valid;

initial begin
  clk = 1'b1;
  rst_n = 1'b0;
  start <= 0;
  #20
  rst_n = 1'b1;
  data_unsort[0] <= 9;
  data_unsort[1] <= 3;
  data_unsort[2] <= 15;
  data_unsort[3] <= 10;
  data_unsort[4] <= 11;
  data_unsort[5] <= 8;
  data_unsort[6] <= 4;
  data_unsort[7] <= 5;
  
  label_unsort[0] <= 0;
  label_unsort[1] <= 1;
  label_unsort[2] <= 2;
  label_unsort[3] <= 3;
  label_unsort[4] <= 4;
  label_unsort[5] <= 5;
  label_unsort[6] <= 6;
  label_unsort[7] <= 7;
  
  #40 start <= 1'b1;
  #20 start <= 1'b0;

end

always #10 clk = ~clk;

bubble_sort
	#(
		.DATA_WIDTH(DATA_WIDTH),
		.LABEL_WIDTH(LABEL_WIDTH),
		.DATA_NUMBER(DATA_NUMBER),
		.ASCEND(ASCEND)
	)
	bubble_sort
	(
		.clk(clk),
		.rst_n(rst_n),
		.start(start),
		.data_unsort({data_unsort[7],data_unsort[6],data_unsort[5],data_unsort[4],data_unsort[3],data_unsort[2],data_unsort[1],data_unsort[0]}),
		.label_unsort({label_unsort[7],label_unsort[6],label_unsort[5],label_unsort[4],label_unsort[3],label_unsort[2],label_unsort[1],label_unsort[0]}),
		
		.data_sorted({data_sorted[7],data_sorted[6],data_sorted[5],data_sorted[4],data_sorted[3],data_sorted[2],data_sorted[1],data_sorted[0]}),
		.label_sorted({label_sorted[7],label_sorted[6],label_sorted[5],label_sorted[4],label_sorted[3],label_sorted[2],label_sorted[1],label_sorted[0]}),
		.data_valid(data_valid)
	);

endmodule

五、仿真结果

  运行仿真程序,得到仿真结果如下。可见排序后的结果与我们理论上的结果一致,仿真通过。
在这里插入图片描述

六、写在后面

  在本文中,我们学习了经典的排序算法——冒泡排序算法的原理及其Verilog代码的实现,冒泡排序算法相比与并行全排序算法和双调排序算法,其时间复杂度要高,性能不佳,所以在实际的应用中很少用到,多用于实验中。
  好了,以上就是关于FPGA中实现冒泡排序的一些学习笔记,如果有疑义的地方欢迎评论区友好探讨学习!!!!!
  代码:(FPGA设计篇之冒泡排序Verilog代码)
在这里插入图片描述

  • 3
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FPGA(现场可编程门阵列)是一种先进的可编程逻辑器件,具备灵活性和高性能的特点。Xilinx是全球著名的FPGA供应商,其开发的器件和工具在FPGA设计中应用广泛。下面将介绍一些FPGA设计高级技巧,特别是在使用Xilinx器件时的应用。 第一个技巧是使用FPGA的高级资源。Xilinx FPGA提供了丰富的高级资源,如DSP48块、BRAM和全局时钟网络等。合理利用这些资源,可以加速设计实现和提高性能。例如,使用DSP48块可以实现并行计算和高速数据处理,使用BRAM可以实现快速的存储操作,使用全局时钟网络可以保证时序一致性。因此,在进行FPGA设计时,需要充分了解芯片的特性和资源,有针对性地进行设计。 第二个技巧是使用IP核。Xilinx FPGA提供了丰富的IP核库,包括处理器、高速接口和加密解密等功能模块。使用IP核可以减少设计周期和复杂度,快速实现设计需求。Xilinx提供了IP核生成器,可以根据设计要求定制IP核。此外,还可以使用第三方IP核,如Xilinx Partner Program中的IP核,进一步丰富功能。 第三个技巧是优化时序。时序优化是FPGA设计中的关键问题。通过合理的时钟分配、时序约束和编码优化等手段,可以提高设计的时序性能。Xilinx提供了时序分析工具和时序约束文件,可以帮助设计人员进行时序分析和优化。此外,还可以使用Xilinx的时序驱动技术,如FPGA中的延迟锁定环(DLL)和锁相环(PLL),来提高时钟频率和时序性能。 总之,FPGA设计高级技巧涉及到多个方面,包括合理利用高级资源、使用IP核和优化时序等。在使用Xilinx器件时,特别需要熟悉相关的开发工具和技术特点,以确保设计的高性能和可靠性。同时,也需要关注FPGA发展趋势和最新的技术,不断提升自己的设计水平。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值