FPGA排序-冒泡排序(Verilog版)介绍

可编程逻辑

1364人已加入

描述

在之前的推文中介绍了冒泡排序的实现,但是分享的代码使用的是SpinalHDL,最近有好多小伙伴后台私信问有没有Verilog版的代码。今天就给大家贴出来,具体原理参考FPGA排序--冒泡排序这篇之前的文章。

仍然以8个8bit的数为例来介绍冒泡排序,因此数据的输入和输出位宽均为64bit(8*8bit),使用valid信号来标识数据有效,整个实现采用流水线的方式。

 

`timescale 1ns / 1ps


module bubble(
    input           clk             ,
    input           rst             ,
    input   [63:0]  data_in         ,
    input           data_in_valid   ,
    output  [63:0]  data_out        ,
    output          data_out_valid


);
    reg [ 3:0]  data_in_valid_ff;
    reg [63:0]  data_in_ff[3:0] ;
    reg         v[7:0][7:0]     ;
    reg [ 1:0]  sum_1[7:0][3:0] ;
    reg [ 2:0]  sum_2[7:0][1:0] ;
    reg [ 3:0]  sum_3[7:0]      ;


    reg [7:0]   data_out_temp[7:0] ;
    reg         data_out_valid_temp;


    genvar i;
    genvar j;




    always @(posedge clk ) begin
        if(rst == 1'b1)begin
            data_in_valid_ff <= 4'b0;
        end
        else begin
            data_in_valid_ff <= {data_in_valid_ff[2:0], data_in_valid};
        end
    end


    always @(posedge clk ) begin
        data_in_ff[0] <= data_in;
    end


    generate
        for ( i = 0; i < 3 ; i = i + 1 ) begin : LOOP_DATA_IN
            always @(posedge clk ) begin
                data_in_ff[i+1] <= data_in_ff[i];
            end
        end
    endgenerate


    generate
        for ( i = 0 ; i < 8 ; i = i + 1 ) begin : LOOP_V_I
            for ( j = i ; j < 8 ; j = j + 1) begin : LOOP_V_J
                always @(posedge clk ) begin
                    if(data_in_valid == 1'b1)begin
                        v[i][j] <= data_in[i*8 +: 8] >= data_in[j*8 +: 8];
                        v[j][i] <= data_in[i*8 +: 8] <  data_in[j*8 +: 8];
                    end
                end
            end
        end
    endgenerate


    generate
        for ( i = 0 ; i < 8 ; i = i + 1 ) begin : LOOP_SUM_1_I
            for ( j = 0 ; j < 4 ; j = j + 1) begin : LOOP_SUM_1_J
                always @(posedge clk ) begin
                    if(data_in_valid_ff[0] == 1'b1)begin
                        sum_1[i][j] <= v[i][j*2] + v[i][j*2 + 1];
                    end
                end
            end
        end
    endgenerate


    generate
        for ( i = 0 ; i < 8 ; i = i + 1 ) begin : LOOP_SUM_2_I
            for ( j = 0 ; j < 2 ; j = j + 1) begin : LOOP_SUM_2_J
                always @(posedge clk ) begin
                    if(data_in_valid_ff[1] == 1'b1)begin
                        sum_2[i][j] <= sum_1[i][j*2] + sum_1[i][j*2 + 1];
                    end
                end
            end
        end
    endgenerate


    generate
        for ( i = 0 ; i < 8 ; i = i + 1 ) begin : LOOP_SUM_3_I
            always @(posedge clk ) begin
                if(data_in_valid_ff[2] == 1'b1)begin
                    sum_3[i] <= sum_2[i][0] + sum_2[i][1];
                end
            end
        end
    endgenerate


    always @(posedge clk ) begin : LOOP_DATA_OUT_TEMP_CLK
        integer k;
        for ( k = 0; k < 8; k = k + 1) begin : LOOP_DATA_OUT_TEMP
            if(data_in_valid_ff[3] == 1'b1)begin 
                data_out_temp[sum_3[k]] <= data_in_ff[3][k*8 +: 8];
                data_out_valid_temp     <= 1'b1;
            end
            else begin
                data_out_temp[sum_3[k]] <= 8'd0;
                data_out_valid_temp     <= 1'b0;
            end
        end
    end


    generate
        for ( i = 0 ; i < 8 ; i = i + 1) begin : LOOP_DATA_OUT
            assign data_out[i*8 +: 8] = data_out_temp[i]   ;
            assign data_out_valid     = data_out_valid_temp;
        end
    endgenerate


endmodule

在代码中用了大量的生成语句,这样可以降低我们的代码量,这些生成语句帮我们生成了大量的重复性电路,我们并不需要有什么担心。

FPGA

仿真代码:

 

`timescale 1ns / 1ps
module tb_bubble(


    );


    reg clk;
    reg rst;


    reg [7:0] data_in_0;
    reg [7:0] data_in_1;
    reg [7:0] data_in_2;
    reg [7:0] data_in_3;
    reg [7:0] data_in_4;
    reg [7:0] data_in_5;
    reg [7:0] data_in_6;
    reg [7:0] data_in_7;


    wire [63:0] data_in;
    reg         data_in_valid;


    wire [63:0] data_out;
    wire        data_out_valid;


    initial begin
        clk = 1'b0;
        rst = 1'b1;
        #50
        rst = 1'b0;
    end


    always #5 clk = !clk;


    always @(posedge clk ) begin
        if(rst == 1'b1)begin
            data_in_0     <= 8'd0;
            data_in_1     <= 8'd0;
            data_in_2     <= 8'd0;
            data_in_3     <= 8'd0;
            data_in_4     <= 8'd0;
            data_in_5     <= 8'd0;
            data_in_6     <= 8'd0;
            data_in_7     <= 8'd0;
            data_in_valid <= 1'b0;
        end
        else begin
            data_in_0     <= {$random} % 255;
            data_in_1     <= {$random} % 255;
            data_in_2     <= {$random} % 255;
            data_in_3     <= {$random} % 255;
            data_in_4     <= {$random} % 255;
            data_in_5     <= {$random} % 255;
            data_in_6     <= {$random} % 255;
            data_in_7     <= {$random} % 255;
            data_in_valid <= 1'b1;
        end
    end


    assign data_in = {data_in_0, data_in_1, data_in_2, data_in_3, data_in_4, data_in_5, data_in_6, data_in_7};


    bubble u_bubble(
        .clk                (clk           ),
        .rst                (rst           ),
        .data_in            (data_in       ),
        .data_in_valid      (data_in_valid ),
        .data_out           (data_out      ),
        .data_out_valid     (data_out_valid)


    );


endmodule


仿真结果:

FPGA

可以看到每个时钟周期输出8个排好序的数字。

FPGA

消耗的资源如上。如果我们不需要流水输出的话,使用的资源可以进一步进行压缩,这个就看具体的需求了,资源和性能的平衡。






审核编辑:刘清

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分