FPGA设计篇之并行全排序

写在前面

  在FPGA设计的过程中,有时候需要对一些数据进行排序,那么常见的排序算法有冒泡排序、并行全排序、双调排序等,它们之间的区别在这里就不进行过多的介绍,本文主要介绍并行全排序算法的原理以及RTL代码实现。

并行全排序算法原理

  并行全排序算法,之所以叫并行全排序算法,是指其各个数据之间的比较的并行执行的。
  并行全排序对于多少个数值的排序,都只需要2个时钟周期,但是随之需要排序数据个数的增加,其资源消耗呈指数上升。并行全排序算法排序的过程包括两个步骤:
  (1)将数据中的每个数据与所有数据进行对比,如果对比结果为若为大于(a > \gt >b),则对比结果为1,否则,为0;
  (2)将步骤一中每个数据与其他数据对比的结果相加,得到值即为对应的大小顺序;

  比如:对四个值1、7、5、2进行排序,那么其结果如下图所示。

在这里插入图片描述
  可见,这里是符合我们预期要求的。但是还有个疑问,如果这组数值中存在两个相等的数值,那么结果会怎么样?比如:对四个值1、7、5、2进行排序,那么其结果如下。

在这里插入图片描述
  这时候,由于用于排序的四个值中有两个都为7,相等,也就导致了这两个值对应的2排序值都为2,这在我们设计的过程中往往是不允许的,因为在多数情况下,我们需要将这个排序值作为其他模块中作为位索引的参数,那么我们对这两个相等的值做出区分,给他们不同的排序值(给第1个7的排序值赋为2,第2个7的排序值赋为3或者是给第1个7的排序值赋为3,第2个7的排序值赋为2)。
  那么,我们通过这样一个办法将其区分:假设第用于对比的值为第i个(i = 0 ~ 3),用于被对比的值为第j个(j = 0 ~ 3),当i > \gt >j时,对比采用大于等于( ⩾ \geqslant )符号进行对比,如果a ⩾ \geqslant b,则对比结果为1,否则,为0;而当i ⩽ \leqslant j时,对比采用大于( > \gt >)符号进行对比,如果a > \gt >b,则对比结果为1,否则,为0。按照这个方法对四个值:1、7、5、7再进行对比,得到排序值如下:

在这里插入图片描述
  那么,这样的作用其实就是:如果用于排序的N个数值中,出现多个相等的值,则将原本序号更大的数值赋予更大的排序值。

并行全排序算法RTL实现

  首先可以设计一个状态机,用于控制排序的进程,主要包括三个状态:初始化、排序、反转。

always @(posedge clk or negedge rst_n)
  if(!rst_n)
	FSM_state_sort <= Initial;
  else 
    case(FSM_state_sort)
	  Initial:
		begin
		  if(sort_sig)
		    FSM_state_sort <= Sort;
		  else
			FSM_state_sort <= Initial;
		end
	  
	  Sort:
		begin
		  if(cnt_sort == 1'd1)
			FSM_state_sort <= Convert;
		  else
			FSM_state_sort <= Sort;
		end
	  
	  Convert:
	    begin
		  FSM_state_sort <= Initial;
		end
	  
	  default: FSM_state_sort <= Initial;
	endcase

  在这里,首先状态机处于初始化状态,如果排序信号sort_sig为高电平,则进入排序状态,而在排序状态下,我们需要进行两个操作:数据两两相比较和对某个数据与其他数据的比较结果进行求和,那么这里需要两个时钟周期,于是在这里设置一个计数器cnt_sort,如果计数器计数到1,则进入反转状态下,将原本每个数据的下标根据排序结果进行调换。
  那么,对数值进行两两并行比较的RTL代码如下:

always @(posedge clk or negedge rst_n)
	if(!rst_n) begin	//复位信号
		for(i=0;i<DN;i=i+1) begin 
			temp[i] = 0;
		end
	end
	else if(sort_sig) begin	//排序开始信号
		for(i=0;i<DN;i=i+1) begin
			for(j=0;j<DN;j=j+1) begin
				if(i>j) begin
					if(data_unsort[i*DW+:DW]>=data_unsort[j*DW+:DW]) 
						temp[i][j] <= 1;
					else	
						temp[i][j] <= 0;
				end
				else begin
					if(data_unsort[i*DW+:DW]>data_unsort[j*DW+:DW])
						temp[i][j] <= 1;
					else
						temp[i][j] <= 0;
				end
			end
		end
	end

  对比较结果求和代码如下:

always @(posedge clk or negedge rst_n)
	if(!rst_n) begin	//复位信号
	  sequence_sorted_temp <= 0;
	end
	else if((FSM_state_sort == Sort) && (cnt_sort == 1'd0)) begin	//序列初始化
	  for(i=0;i<DN;i=i+1) begin
		sequence_sorted_temp[i*DW_sequence+:DW_sequence] <= i;
	  end
	end
	else if(cnt_sort == 1'd1) begin //更新序列
	  for(i=0;i<DN;i=i+1) begin
	    sequence_sorted_temp[i*DW_sequence+:DW_sequence] <= temp[i][0]+temp[i][1]+temp[i][2]+temp[i][3]+temp[i][4]+temp[i][5]+temp[i][6]+temp[i][7]; 
	  end
	end
	else
		sequence_sorted_temp <= sequence_sorted_temp;

  根据排序结果对原本每个数据对应的下标进行调换代码如下:

always @(posedge clk or negedge rst_n)
  if(!rst_n)
	sequence_sorted <= 0;
  else if(FSM_state_sort == Convert)
	for(i=0;i<DN;i=i+1) begin
	  sequence_sorted[sequence_sorted_temp[i*DW_sequence+:DW_sequence]*DW_sequence+:DW_sequence] <= i; 
	end 
  else
    sequence_sorted <= sequence_sorted;

Test_Bench

  仿真代码如下。

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

//--------------------------------------------
//参数定义
//--------------------------------------------		
	parameter DW = 8; //数据位宽
	parameter DN = 8; //数据个数
	parameter DW_sequence = $clog2(DN); //序号位宽

//--------------------------------------------
//端口定义
//--------------------------------------------	
	reg 					clk,rst_n;
	reg						sort_sig;
	reg		[DW*DN-1:0]		data_unsort;
	wire	[DW_sequence*DN-1:0]	sequence_sorted;
	wire						sort_finish;
	
	wire	[DW_sequence-1:0]	sequence_sorted_0;
	wire	[DW_sequence-1:0]	sequence_sorted_1;
	wire	[DW_sequence-1:0]	sequence_sorted_2;
	wire	[DW_sequence-1:0]	sequence_sorted_3;
	wire	[DW_sequence-1:0]	sequence_sorted_4;
	wire	[DW_sequence-1:0]	sequence_sorted_5;
	wire	[DW_sequence-1:0]	sequence_sorted_6;
	wire	[DW_sequence-1:0]	sequence_sorted_7;
	
	assign sequence_sorted_0 = sequence_sorted[0*DW_sequence+:DW_sequence];
	assign sequence_sorted_1 = sequence_sorted[1*DW_sequence+:DW_sequence];
	assign sequence_sorted_2 = sequence_sorted[2*DW_sequence+:DW_sequence];
	assign sequence_sorted_3 = sequence_sorted[3*DW_sequence+:DW_sequence];
	assign sequence_sorted_4 = sequence_sorted[4*DW_sequence+:DW_sequence];
	assign sequence_sorted_5 = sequence_sorted[5*DW_sequence+:DW_sequence];
	assign sequence_sorted_6 = sequence_sorted[6*DW_sequence+:DW_sequence];
	assign sequence_sorted_7 = sequence_sorted[7*DW_sequence+:DW_sequence];

//--------------------------------------------
//初始信号值
//--------------------------------------------
    
	initial		
		begin
			clk = 0;
			rst_n = 0;
			sort_sig = 1'b0;

			#5
			#10 rst_n = 1;
			#10 sort_sig = 1'b1;
			data_unsort[DW*0+:DW] = 'd29; //6
			data_unsort[DW*1+:DW] = 'd19; //2
			data_unsort[DW*2+:DW] = 'd9 ; //0
			data_unsort[DW*3+:DW] = 'd22; //3
			data_unsort[DW*4+:DW] = 'd27; //4
			data_unsort[DW*5+:DW] = 'd28; //5
			data_unsort[DW*6+:DW] = 'd92; //7
			data_unsort[DW*7+:DW] = 'd9 ; //1
			#10 sort_sig = 1'b0;
			
			#1600
			$stop;
		end
	always #5 clk <= ~clk;

//--------------------------------------------
//模块例化
//--------------------------------------------
parallel_sort
#(	
	.DN (DN ),
	.DW	(DW	)
)
parallel_sort_inst
(
	.clk(clk),
	.rst_n(rst_n),
	.sort_sig(sort_sig),
	
	.data_unsort(data_unsort),
	.sequence_sorted(sequence_sorted),
	.sort_finish(sort_finish)
);


endmodule

仿真结果

  在这里我们以8个数为例,这8个数分别为: a 0 a_0 a0=29, a 1 a_1 a1=19, a 2 a_2 a2=9, a 3 a_3 a3=22, a 4 a_4 a4=27, a 5 a_5 a5=28, a 6 a_6 a6=92, a 7 a_7 a7=9。那么,对这组数据进行升序排列后的结果应该是 a 2 a_2 a2( a 7 a_7 a7)< a 1 a_1 a1< a 3 a_3 a3< a 4 a_4 a4< a 5 a_5 a5< a 0 a_0 a0< a 6 a_6 a6,运行Test_Bench,得到以下结果,可见与我们理论上排序的结果一致,且只需要3个时钟周期,仿真通过。

在这里插入图片描述

写在最后

  并行全排序是一种使用面积换速度的排序算法,无论对于多大的数据集,其排序时间仅需3个时钟周期,但是对于数据集中数据个数的上升,其电路面积呈指数上升,所以对于含有少量数据的数据集的排序,并行全排序是一种可选的方案。
  好了,上面就是关于FPGA中实现并行全排序的一些学习笔记,如果有疑义的地方欢迎评论区友好探讨学习!!!!!(RTL代码)
在这里插入图片描述

  • 4
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
Verilog 并行排序算法是一种在 Verilog 语言中实现的用于对数据进行并行排序的算法。该算法以并行的方式对数据进行排序,提高了排序过程的效率和速度。 在 Verilog 中,可以使用并行排序算法来对数据进行排序,其中最常用的算法是并行插入排序算法。该算法通过将待排序的数据分成多个小部分并在不同的处理单元中进行并行比较和交换,最终合并排序结果。这种并行排序算法的特点是可以充分利用系统中的多个处理单元,从而加快排序速度。 具体实现并行排序算法需要设计具体的硬件模块,在 Verilog 中可以使用模块化的设计风格来构建并行排序模块。首先,需要将待排序的数据拆分成多个子集,并在每个子集中进行局部排序。然后,使用比较器和交换模块对子集进行并行比较和交换操作。最后,使用合并模块将子集中的排序结果合并成最终的排序结果。 在实际应用中,可以将并行排序算法应用于对大规模数据进行排序的场景,如图像处理、数据挖掘和通信等领域。通过并行排序算法,可以提高排序的速度和效率,从而更好地应对大规模数据处理的需求。 总而言之,Verilog 并行排序算法是一种在 Verilog 语言中实现的用于对数据进行并行排序的算法。它可以通过并行处理多个子集中的排序操作来提高排序速度和效率,适用于处理大规模数据的场景。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值