FPGA篇(三)基于FPGA的几种排序算法

https://blog.csdn.net/yanchuan23/article/details/79780605

 

目录

1      冒泡法和比较排序法

1.1        算法原理

1.2        仿真结果

1.3        算法优缺点

2      并行全比较排序法

2.1        算法原理及Verilog实现

2.2        仿真结果

2.3    算法优缺点

3      串行全比较排序法

3.1        算法原理及Verilog实现

3.2       仿真结果

3.3       算法优缺点

2      总结

 

最近笔者在项目中正好遇到需要排序的情况,以前刚接触C语言的时候排序的方法主要有冒泡排序、选择排序等方法;于是就用Verilog实现了冒泡法,但是发现此方法和选择排序法需要的时间周期太长,比如16个数据差不多需要136个周期才能完成排序,于是笔者在网上找到了并行全比较排序法和改进的串行全比较排序法;以下将一一介绍。

 

1      冒泡法和比较排序法
 

1.1        算法原理
 

这两种方法比较容易理解,下面给出两种排序方法的百科连接,大家可以自行百度。

冒泡排序:

https://baike.baidu.com/item/%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F

 

 

选择排序:

https://baike.baidu.com/item/%E9%80%89%E6%8B%A9%E6%8E%92%E5%BA%8F%E6%B3%95/2304587?fr=aladdin

 

1.2        仿真结果
 

        下面给出冒泡法的Verilog仿真结果,蓝色箭头是输入的原始数据,红色箭头所指的是排完序的数据,黄色箭头指的是排序所用的时间,仿真用的是100MHz的始终,所以冒泡总共需要136个周期。

 

1.3        算法优缺点
 

    选择排序法和冒泡法属于传统的两两比较的算法,但是消耗的周期比较长,在一些对实时性要求较高的情况下无法满足要求。

 

2      并行全比较排序法
2.1        算法原理及Verilog实现
        传统的排序方式是以两两之间顺序比较为基础,而并行全比较实时排序算法是基于序列中任意两个数并行比较实现。由于从原来的串行比较变成了并行比较,所以需要消耗比以前多的比较器,诠释了FPGA中“用面积换速度”的思想。以序列长度为m的数据为例:

A:    第一个时钟周期:将其中一个数据和其他数据在一个周期中一一比较,比较器分三种情况:

    1.        这个数据大于其他数据,则它的得分为0;

    2.        这个数据等于其他数据,若它在这个序列中比和它相等的其他数据靠前,则它的得分为0,反之为1;

    3.        这个数据小于其他数据,则它的得分为1;

//--------------------------            计算得分        ----------------------------------
    generate
        genvar i;
            for(i=1;i<=COL_WIDTH;i=i+1)
                begin:unfold_i
                    always@(posedge    clk    or    posedge    rst)
                        begin
                            if(rst)
                                begin    
                                    comp_valid_i[i] <= 0;
                                    score_i[i] <= 0;    
                                end
                            else    if(comp_valid_f)
                                begin
                                    if(comp_data[col] > comp_data[i])
                                        score_i[i] <= 0;
                                    else    if(comp_data[col] == comp_data[i])
                                        begin
                                            if(col <= i) //如果有两个相同的数据,其中若输入顺序在前面则排序就靠前
                                                score_i[i] <= 0;
                                            else
                                                score_i[i] <= 1;
                                        end
                                    else    
                                        score_i[i] <= 1;
                                    comp_valid_i[i] <= comp_valid_f;
                                end
                            else
                                begin
                                    score_i[i] <= 0;
                                    comp_valid_i[i] <= 0;
                                end
                        end
                end
    endgenerate
 

 

B:第二个时钟周期:将每个数据和其他数据比较后的数据累加;

 

 

    always@(posedge    clk    or posedge    rst)
        begin
            if(rst)
                begin
                    score <= 0;
//                    score_t[1]<=0;
//                    score_t[2]<=0;
                    location <= 0;
                    add_cnt <= 0;
                    data_o <= 0;
                    valid_o <= 0;
                end
            else    if(comp_valid_j[1] == 1)
                begin
                    add_cnt <= 0;
//                    add_cnt <= 1;
//                    score_t[1] <= ( score_j[1]+score_j[2] ) + ( score_j[3]+score_j[4] );
//                    score_t[2] <= ( score_j[5]+score_j[6] ) + ( score_j[7]+score_j[8] );
                    score     <= ( ( score_j[1]+score_j[2] ) + ( score_j[3]+score_j[4] ) )+
                                 ( ( score_j[5]+score_j[6] ) + ( score_j[7]+score_j[8] ) )+
                                 ( ( score_j[9]+score_j[10] ) + ( score_j[11]+score_j[12] ) )+
                                 ( ( score_j[13]+score_j[14] ) + ( score_j[15]+score_j[16] ) )+ 1;
                    location <= {row[7:0],col[7:0]};//行,列
                    data_o <= comp_data[col];//数据
                    valid_o <= 1;
                end
end
 

C: 第三个时钟周期:将每个数据根据自己的得分赋值给新的数组(若得分为1的就赋值给数组中的第一个数,2就赋值给新的数组中第二个数);

 

//--------------------------------------------------------------------------------
    always@(posedge    clk    or posedge    rst)
        begin
            if(rst)
                begin
                    sort_done <= 0; //数据的坐标    
                end
            else    if(valid_o[1])
                begin
                    chn[score[1]] <= data_o[1]; //重新排列的数据    
                    chn[score[2]] <= data_o[2]; //重新排列的数据
                    chn[score[3]] <= data_o[3]; //重新排列的数据
                    chn[score[4]] <= data_o[4]; //重新排列的数据
                    chn[score[5]] <= data_o[5]; //重新排列的数据
                    chn[score[6]] <= data_o[6]; //重新排列的数据
                    chn[score[7]] <= data_o[7]; //重新排列的数据
                    chn[score[8]] <= data_o[8]; //重新排列的数据
                    chn[score[9]] <= data_o[9]; //重新排列的数据
                    chn[score[10]] <= data_o[10]; //重新排列的数据
                    chn[score[11]] <= data_o[11]; //重新排列的数据
                    chn[score[12]] <= data_o[12]; //重新排列的数据
                    chn[score[13]] <= data_o[13]; //重新排列的数据
                    chn[score[14]] <= data_o[14]; //重新排列的数据
                    chn[score[15]] <= data_o[15]; //重新排列的数据
                    chn[score[16]] <= data_o[16]; //重新排列的数据
                    sort_done <= 1;
                end
            else
                begin
                    sort_done <= 0;
                end
        end    
 

D:  第四个时钟周期:将新数组输出;

 

经过以上四个步骤,即可将算法完成。

 

2.2        仿真结果


 

        如上图所示,红色箭头代表着输入数据,其中红色的圈标记出输入相同的两个数据;黄色箭头为每个数据与别的数据比较后的得分,得分越小则代表这个数据越大,其中黄色部分是第一个数据和第二个数据的得分,这两个数据的大小是一样的,但是第一个数据输入数组中比第二个数据靠前,所以它的得分低一分,这也验证了我们设计逻辑上在是正确的;蓝色箭头则代表的是排完序的输出序列,经观察发现结果正确。

 

2.3    算法优缺点
l  优点:并行比较排序方式在实时性上有明显的优势,只需要四个时钟周期就可以排序完成;

l  缺点:

        1.        由于是并行比较消耗了较多的资源,而且在第二个时钟周期(得分累加)需要大量的加法器级联,考虑到路径延迟、建立保持时间和时钟抖动,一个时钟周期许多个加法器级联会有问题;

        2.        在代码可移植性方面也有欠缺,比如若序列大小改变,在第二个和第三个时钟周期的时候就需要人为修改多处代码;

 

3      串行全比较排序法
3.1        算法原理及Verilog实现
        串行全比较排序法在并行全比较排序法做了一些改进,将原来并行全比较排序法的前三个周期由并行转变为串行,但是可以在比较的同时将得分累加,所以串行全比较排序法排序需要的周期是2*m(m个序列)个周期。

//--------------------------------------------------------------------------------
    always@(posedge    clk    or posedge    rst)
        begin
            if(rst)
                begin
                    comp_cnt <= COL_WIDTH + 1;
                    score <=    1;
                    valid_o <=    0;
                end
            else    if(comp_cnt <= COL_WIDTH)
                begin
                    comp_cnt <= comp_cnt + 1;
                    
                    if(comp_data[col] > comp_data[comp_cnt])
                        score <= score;
                    else    if(comp_data[col] == comp_data[comp_cnt])
                        begin
                            if(col <= comp_cnt)
                                score <= score;
                            else
                                score <= score + 1;
                        end
                    else        
                        score <= score + 1;
                    
                    if(comp_cnt == COL_WIDTH)    valid_o <=    1;
                    else        valid_o <=    0;
                end
            else    if(valid_r)
                begin
                    comp_cnt <= 1;
                    score <= 1;
                    valid_o <=    0;
                end
            else
                begin
                    comp_cnt <= comp_cnt;
                    score <= score;
                    valid_o <=    0;
                end
        end
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
    always@(posedge    clk    or posedge    rst)
        begin
            if(rst)
                begin
                    sort_count <= COL_WIDTH + 1;
                    sort_done <= 0;
                end
            else    if(sort_count <= COL_WIDTH)
                begin
                    sort_count <= sort_count + 1;
                    comp_data_index[score[sort_count]] <= comp_data[sort_count]; //这边改成DPR_RAM
                    if(sort_count == COL_WIDTH)
                        sort_done <= 1;
                    else        
                        sort_done <= 0;
                end
            else    if(valid_o[1])
                begin
                    sort_count <= 1;
                    sort_done <= 0;
                end
            else
                begin
                    sort_count <= sort_count;
                    sort_done <= 0;
                end
        end
//--------------------------------------------------------------------------------
3.2       仿真结果


 

 

 

 

 

        如上图所示,红色箭头代表着输入数据;黄色箭头为每个数据与别的数据比较后的得分;蓝色箭头则代表的是排完序的输出序列,经观察发现结果正确。

        从图中可以读出排序需要的时间是330ns,由于仿真采用的时钟是100MHz,所以串行全比较算法需要33个时钟周期(大约2*n个周期)。

3.3       算法优缺点
串行全比较算法和并行全比较算法比较:

l  优点:

        1.        资源消耗的比较少;

        2.        代码可移植性好,序列变化只需要改变几个参数,不需要大规模修改代码;

l  缺点:

        串行全比较算法所消耗的时间比并行全比较算法长。

2      总结
l  代码可移植性:传统串行排序算法>串行全比较排序法>并行全比较排序法

l  资源使用:传统串行排序算法<串行全比较排序法<并行全比较排序法

l  排序时间:并行全比较排序法<串行全比较排序法<传统串行排序算法
--------------------- 
作者:Nemo_yxc 
来源:CSDN 
原文:https://blog.csdn.net/yanchuan23/article/details/79780605 
版权声明:本文为博主原创文章,转载请附上博文链接!

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值