FPGA设计篇之并行全排序

  • 写在前面
  • 并行全排序算法原理
  • 并行全排序算法RTL实现
  • Test_Bench
  • 仿真结果
  • 写在最后

写在前面

  在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:beginif(sort_sig)FSM_state_sort <= Sort;elseFSM_state_sort <= Initial;endSort:beginif(cnt_sort == 1'd1)FSM_state_sort <= Convert;elseFSM_state_sort <= Sort;endConvert:beginFSM_state_sort <= Initial;enddefault: 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;endendelse if(sort_sig) begin    //排序开始信号for(i=0;i<DN;i=i+1) beginfor(j=0;j<DN;j=j+1) beginif(i>j) beginif(data_unsort[i*DW+:DW]>=data_unsort[j*DW+:DW]) temp[i][j] <= 1;else   temp[i][j] <= 0;endelse beginif(data_unsort[i*DW+:DW]>data_unsort[j*DW+:DW])temp[i][j] <= 1;elsetemp[i][j] <= 0;endendendend

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

always @(posedge clk or negedge rst_n)if(!rst_n) begin  //复位信号sequence_sorted_temp <= 0;endelse if((FSM_state_sort == Sort) && (cnt_sort == 1'd0)) begin   //序列初始化for(i=0;i<DN;i=i+1) beginsequence_sorted_temp[i*DW_sequence+:DW_sequence] <= i;endendelse if(cnt_sort == 1'd1) begin //更新序列for(i=0;i<DN;i=i+1) beginsequence_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]; endendelsesequence_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) beginsequence_sorted[sequence_sorted_temp[i*DW_sequence+:DW_sequence]*DW_sequence+:DW_sequence] <= i; end elsesequence_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       beginclk = 0;rst_n = 0;sort_sig = 1'b0;#5#10 rst_n = 1;#10 sort_sig = 1'b1;data_unsort[DW*0+:DW] = 'd29; //6data_unsort[DW*1+:DW] = 'd19; //2data_unsort[DW*2+:DW] = 'd9 ; //0data_unsort[DW*3+:DW] = 'd22; //3data_unsort[DW*4+:DW] = 'd27; //4data_unsort[DW*5+:DW] = 'd28; //5data_unsort[DW*6+:DW] = 'd92; //7data_unsort[DW*7+:DW] = 'd9 ; //1#10 sort_sig = 1'b0;#1600$stop;endalways #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代码)

FPGA设计篇之并行全排序相关推荐

  1. FPGA设计篇之双调排序

    FPGA设计篇之双调排序(Bitonic Sort) 一.写在前面 二.双调排序算法原理 2.1 双调序列 2.2 Batcher定理 2.3 双调排序算法 2.4 构造双调序列 三.双调排序算法RT ...

  2. FPGA设计篇之流水线思想

    FPGA设计篇之流水线思想 一.写在前面 二.正文开始 2.1举个栗子 2.2.1情况一(组合逻辑) 2.1.2情况二(流水线设计) 2.1.4 小总结 2.2举第二个栗子 写在最后 一.写在前面   ...

  3. 读论文之《基于 FPGA 的并行全比较排序算法》

    为什么介绍这种排序算法:最近在独立编写霍夫曼编码的verilog HDL设计程序,其中用到了排序模块,对一组数据进行排序,苦寻几天,最终找到了这个全新的适合硬件实现的排序算法,分享与此,以空间换时间的 ...

  4. 基于 FPGA 的并行全比较排序算法,topK

    以空间换时间的并行排序算法. https://blog.csdn.net/Reborn_Lee/article/details/80469391 并行全比较排序算法介绍 排序是一种重要的数据运算,传统 ...

  5. 华为FPGA设计高级技巧xilnx篇-阅读笔记2

    华为FPGA设计高级技巧xilnx篇-阅读笔记2 设计技巧 合理选择加法电路 串行进位与超前进位 使用圆括号处理多个加法器 IF语句和Case语句:速度与面积的关系. 减少关键路径的逻辑级数 通过等效 ...

  6. C#算法设计排序篇之04-选择排序(附带动画演示程序)

    选择排序(Selection Sort) 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/681 访问. 选择排序是一种简 ...

  7. FPGA设计实战演练(高级技巧篇)

    初学者,不太建议读这本书,你会感觉FPGA设计好复杂,等在你做过2个项目之后,在慢慢体会这些书里的设计理念,可能慢慢就懂了.

  8. FPGA设计-时序约束(上篇,理论篇)

    最近想要同步CSDN和微信公众号的内容,各位看客们可以两边都关注一下,方便获取最新的信息.请扫描下面的的二维码添加关注,谢谢支持. 最近都在做ARM的方面学习工作,感觉有必要记录下来之前FPGA的工作 ...

  9. FPGA设计思想与技巧(转载)

    题记:这个笔记不是特权同学自己整理的,特权同学只是对这个笔记做了一下完善,也忘了是从那DOWNLOAD来的,首先对整理者表示感谢.这些知识点确实都很实用,这些设计思想或者也可以说是经验吧,是很值得每一 ...

最新文章

  1. Latex常用数学符号
  2. JVM加载class文件的原理简述
  3. 实验结果报告与实验总结_教科版科学四年级上册实验报告
  4. 推荐10个Github热门Python库,非常实用!
  5. 前台特效(9)无限极分类折叠菜单
  6. 文件夹操作之判断是否存在(Directory)
  7. Spotify模式并非“敏捷涅磐”
  8. 博客园添加鼠标粒子吸附特效
  9. linux中如何设置用户自己的工作环境,Linux系统下设置用户登录环境
  10. Docker容器虚拟化与传统虚拟机比较
  11. Error in mounted hook: “TypeError: Cannot read properties of undefined (reading ‘i
  12. LRC软件测试简历,C语言 LRC歌词文件解析
  13. 如何在vim中打印出^M
  14. 从物联网到元宇宙 PPT
  15. windows10搭建DVWA靶场(新手向)
  16. 游戏史上80重要创新(原资料来自17173)
  17. 基于AD603的AGC电路
  18. 学测绘和计算机,测绘工程就业方向与前景 女生学测绘好找工作吗
  19. 《Read, Listen, and See: Leveraging Multimodal Information Helps Chinese Spell Checking》阅读记录
  20. Zookeepr分布式协调服务之基础铺垫(大数据工程师工作笔记)

热门文章

  1. Hadoop中的shuffle、partition和combiner
  2. 工具|MySQL、Redis、MongoDB网络抓包工具
  3. DevExpress 第三方控件汉化
  4. (六)多线程说学逗唱:线程的暂停与其优先级
  5. 首届微软研究峰会视频上线,快来查收你的独家观看指南!
  6. int linux 原子操作_Linux原子操作
  7. VBA如何遍历文件夹下面的所有文件
  8. 蚂蚁风险大脑亮相ATEC城市峰会:为数字经济时代做好“安全守护”
  9. 显示器切换服务器用什么键,电脑显示器切换器购买要注意什么 哪款电脑切换器好用...
  10. educoder数据结构 树 第1关:由双遍历序列构造二叉树