FPGA设计篇之双调排序(Bitonic Sort)

  • 一、写在前面
  • 二、双调排序算法原理
    • 2.1 双调序列
    • 2.2 Batcher定理
    • 2.3 双调排序算法
    • 2.4 构造双调序列
  • 三、双调排序算法RTL实现
  • 四、Test_bench
  • 五、仿真结果
  • 六、写在后面

一、写在前面

  在前面,我们介绍了并行全排序算法的原理及RTL级设计,在本文中将继续介绍另外一种排序算法——双调排序算法(Bitonic Sort)的基本原理及其实现。双调排序算法是一种用于排序的并行算法,该算法由Ken Batcher提出。对于含有N个元素的排序网络,该网络中总共需要(N/2)*log2N个排序器,排序时间复杂度为log2N。

二、双调排序算法原理

2.1 双调序列

  在讲解双调排序算法前,我们需要了解一个概念——双调序列。双调序列(Botonic Sequence)是指一个由一个非严格增序列X和非严格减序列Y构成的序列,比如序列:2,5,7,12,13,11,6,3或者11,6,3,2,5,7,12,13。这里有一点需要注意的是:双调序列只要求序列是由一个增序列和减序列构成的,并不要求先减后增还是先增后减,也并不要求增序列和减序列等长。

2.2 Batcher定理

  Batcher定理:将一个任意长为2N的双调序列a等分为两个等长的序列X和Y,将X中的元素和Y中的元素按照原序进行比较,即将a[i]与a[i+N]进行比较,将较大者放入MAX序列,较小者放入MIN序列,则得到的MAX序列和MIN序列仍然是双调序列,并且MAX序列中的任意一个元素不小于MIN序列中的任意一个元素。
  比如序列:3,5,9,10,14,15,11,8,该序列为长度为8的双调序列,其中,序列:3,5,9,10,14,15是增序列,序列:11,8是减序列,将序列等分为两个长度为4的序列,序列一:3,5,9,10;序列二:14,15,11,8,按照顺序将序列一和序列二进行一 一对比,得到MIN序列和MAX序列,其中,MIN序列:3,5,9,8;MAX序列:14,15,11,10。可见,MIN序列与MAX序列均为双调序列,且MAX序列中的任意一个元素均大于MIN序列中的任意一个元素,如下图所示。

2.3 双调排序算法

  根据上面提到的Batcher定理,我们可以知道:将一个长度为N的双调序列进行双调排序可以得到两个长度为N/2的双调序列MAX序列和MIN序列,且MAX序列中的值一定不小于MIN序列中的值。那么,由于MAX序列和MIN序列均为双调序列,可以对这两个序列再进行双调排序,MAX序列进行双调排序后得到一个MAXMAX序列和一个MINMAX序列,其中,MAXMAX序列和MINMAX序列的长度均为N/4,且MAXMAX序列中的任意元素的值大于等于MINMAX序列中任意一个元素的值;MIN序列进行双调排序后得到一个MAXMIN序列和一个MINMIN序列,其中MAXMIN序列和MINMIN序列的长度同样为N/4,且MAXMIN序列中的任意一个元素的值大于MINMIN序列中任意一个元素的值。
  那么,经过两层的双调排序后,我们得到了4个长度为N/4的双调序列:MAXMAX序列、MINMAX序列、MAXMIN序列、MINMIN序列。这4个序列中任意元素之间的关系如下:
MAXMAX序列 ≥ \geq ≥ MINMAX序列 ≥ \geq ≥ MAXMIN序列 ≥ \geq ≥ MINMIN序列
  那么对这4个长度为N/4的双调序列再进行排序,得到依次递增的8个长度为N/8的双调序列(注意:这8个序列之间是依次递增的关系,但是这8个序列内部的数值并不是递增的,而是双调的,即先增后减或者先减后增的序列),按照这个方法一直进行log2N层的双调排序,即可得到排序后的序列。
  以上面的长度为8的双调序列:3,5,9,10,14,15,11,8为例,对该序列进行双调排序后得到两个长度为4的双调序列MAX序列和MIN序列,其中,MIN序列:3,5,9,8,MAX序列:14,15,11,10,对MIN序列和MAX序列再分别进行双调排序,得到MINMIN序列:3 , 5 ;MINMAX序列:9,8 ;MAXMIN序列:11,10 ; MAXMAX序列:14,15,如下图所示。

  对这4个长度为2的双调序列再分别进行双调排序,即可得到我们需要的排序结果,如下图所示。这里总共进行了log28=3层的双调排序

  上面用的是升序排序,也可以使用降序排序,得到的排序结果如下图所示。


  上面,分别示意了升序排序符号和降序排列符号,其符号示意图如下。

2.4 构造双调序列

  那么,在我们的日常中,需要进行排序的数据一般都是随机的,并不是双调序列。那么,如果不是双调序列,而是随机生成的序列,双调排序算法是否适用?答案是适用,但是需要先把随机序列转换为双调序列,然后才能使用双调排序算法进行排序,这个过程我们称之为Bitonic Merge。
  首先,对于一个长度为2的任意序列,该序列必然是双调序列。而要生成一个长度为4的双调序列,我们只需要让两个长度为2的双调序列单调性相反即可,即一个为增序列,一个为减序列。那么,要如何实现一个为增序列一个为降序列?在前面的双调排序部分,我们知道:对一个长度为N的双调序列进行升序双调排序,即可得到一个长度为N的增序列,而对该序列进行降序双调排序,即可得到一个长度为N的减序列。所以在这里,我们可以分别对这两个长度为2的双调序列进行升序双调排序和降序双调排序,即可得到一个长度为4的双调序列,如下图所示。


  那么,对于两个长度为4的双调序列,怎么合成一个长度为8的双调序列?与前面一致,对其中一个双调序列进行升序双调排序,一个进行降序双调排序,即可得到一个长度为8的双调序列,如下图所示。

  所以,对于一个长度为8的随机序列,经过两次的双调排序,即可得到一个长度为8的双调序列,如下图所示。


  综上所述,对于一个长度为N的随机序列,要构造成长度为N的双调序列,可以总结以下几点:
(1)构造一个长度为N的双调序列可以通过两个长度为N/2的单调性相反的序列进行拼接的得到,而长度为N/2的单调序列可以由长度为N/4的双调序列进行双调排序(升序双调排序或者降序双调排序)得到,而长度为N/4的双调序列又可以通过拼接两个长度为N/8的单调性相反的序列得到,而长度为N/8的单调序列又可以由长度为N/4的双调序列进行双调排序(升序双调排序或者降序双调排序)得到…以此类推,直至长度为2的序列,长度为2的序列必然为双调序列。
(2)对于一个长度为N的随机序列,构造成双调序列总共需要 log2N-1 次的双调排序,而所需的比较器个数为
2.5 小结
  综上所述,对一个随机的序列进行双调排序主要包括两个步骤:(1)构造双调序列;(2)对双调序列进行排序;那么,对于N=8的情况,对其进行升序排序,其排序网络结构如下图所示。

  采用降序双调排序,则排序网络结构如下图所示。

三、双调排序算法RTL实现

  那么,根据上面讲解的双调排序的基本原理,我们可以编写对应的代码。
  首先,我们可以编写编写基本的排序单元——二输入排序单元,可以实现升序排序或者是降序排序,实现对数值以及数值对应的标签进行排序,如下。其中,可以通过参数ASCEND来控制排序器采用升序排序还是降序排序。

module input_2_sequencer
#(parameter DATA_WIDTH = 8,parameter   LABEL_WIDTH = 4,parameter  DATA_NUMBER = 2,parameter  ASCEND = 1
)
(clk,rst_n,data_unsort,label_unsort,data_sorted,label_sorted
);input                                 clk;
input                                   rst_n;
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;always @(posedge clk or negedge rst_n)if(!rst_n)data_sorted <= 0;else beginif(ASCEND == 1) //升序排序if(data_unsort[DATA_WIDTH-1:0] < data_unsort[2*DATA_WIDTH-1:DATA_WIDTH]) begindata_sorted[DATA_WIDTH-1:0] <= data_unsort[DATA_WIDTH-1:0];data_sorted[2*DATA_WIDTH-1:DATA_WIDTH] <= data_unsort[2*DATA_WIDTH-1:DATA_WIDTH];label_sorted[LABEL_WIDTH-1:0] <= label_unsort[LABEL_WIDTH-1:0];label_sorted[2*LABEL_WIDTH-1:LABEL_WIDTH] <= label_unsort[2*LABEL_WIDTH-1:LABEL_WIDTH];end else begindata_sorted[DATA_WIDTH-1:0] <= data_unsort[2*DATA_WIDTH-1:DATA_WIDTH];data_sorted[2*DATA_WIDTH-1:DATA_WIDTH] <= data_unsort[DATA_WIDTH-1:0];label_sorted[LABEL_WIDTH-1:0] <= label_unsort[2*LABEL_WIDTH-1:LABEL_WIDTH];label_sorted[2*LABEL_WIDTH-1:LABEL_WIDTH] <= label_unsort[LABEL_WIDTH-1:0];endelse if(ASCEND == 0) //降序排序if(data_unsort[DATA_WIDTH-1:0] < data_unsort[2*DATA_WIDTH-1:DATA_WIDTH]) begindata_sorted[DATA_WIDTH-1:0] <= data_unsort[2*DATA_WIDTH-1:DATA_WIDTH];data_sorted[2*DATA_WIDTH-1:DATA_WIDTH] <= data_unsort[DATA_WIDTH-1:0];label_sorted[LABEL_WIDTH-1:0] <= label_unsort[2*LABEL_WIDTH-1:LABEL_WIDTH];label_sorted[2*LABEL_WIDTH-1:LABEL_WIDTH] <= label_unsort[LABEL_WIDTH-1:0];end else begindata_sorted[DATA_WIDTH-1:0] <= data_unsort[DATA_WIDTH-1:0];data_sorted[2*DATA_WIDTH-1:DATA_WIDTH] <= data_unsort[2*DATA_WIDTH-1:DATA_WIDTH];label_sorted[LABEL_WIDTH-1:0] <= label_unsort[LABEL_WIDTH-1:0];label_sorted[2*LABEL_WIDTH-1:LABEL_WIDTH] <= label_unsort[2*LABEL_WIDTH-1:LABEL_WIDTH];end  endendmodule

  而四输入的双调排序器可以由四个二输入的排序器构成,如下。

module input_4_sequencer
#(parameter DATA_WIDTH = 8,parameter   LABEL_WIDTH = 4,parameter  DATA_NUMBER = 4,parameter  ASCEND = 1
)
(clk,rst_n,data_unsort,label_unsort,data_sorted,label_sorted
);input                                 clk;
input                                   rst_n;
input   [DATA_NUMBER*DATA_WIDTH-1:0]    data_unsort;
input   [DATA_NUMBER*LABEL_WIDTH-1:0]   label_unsort;output [DATA_NUMBER*DATA_WIDTH-1:0]    data_sorted;
output  [DATA_NUMBER*LABEL_WIDTH-1:0]   label_sorted;wire   [DATA_NUMBER*DATA_WIDTH-1:0]    data_sorted_stage_2;
wire    [DATA_NUMBER*DATA_WIDTH-1:0]    data_sorted_stage_1;
wire    [DATA_NUMBER*LABEL_WIDTH-1:0]   label_sorted_stage_2;
wire    [DATA_NUMBER*LABEL_WIDTH-1:0]   label_sorted_stage_1;genvar i,j;
// Stage 2
generatefor(i=0;i<DATA_NUMBER/2;i=i+1) begininput_2_sequencer#(.DATA_WIDTH(DATA_WIDTH),.LABEL_WIDTH(LABEL_WIDTH),.DATA_NUMBER(2),.ASCEND(ASCEND))stage_2(.clk(clk),.rst_n(rst_n),.data_unsort({data_unsort[(i+DATA_NUMBER/2)*DATA_WIDTH+:DATA_WIDTH],data_unsort[i*DATA_WIDTH+:DATA_WIDTH]}),.label_unsort({label_unsort[(i+DATA_NUMBER/2)*LABEL_WIDTH+:LABEL_WIDTH],label_unsort[i*LABEL_WIDTH+:LABEL_WIDTH]}),.data_sorted({data_sorted_stage_2[(i+DATA_NUMBER/2)*DATA_WIDTH+:DATA_WIDTH],data_sorted_stage_2[i*DATA_WIDTH+:DATA_WIDTH]}),.label_sorted({label_sorted_stage_2[(i+DATA_NUMBER/2)*LABEL_WIDTH+:LABEL_WIDTH],label_sorted_stage_2[i*LABEL_WIDTH+:LABEL_WIDTH]}));end
endgenerate// Stage 1
generatefor(j=0;j<2;j=j+1) begininput_2_sequencer#(.DATA_WIDTH(DATA_WIDTH),.LABEL_WIDTH(LABEL_WIDTH),.DATA_NUMBER(DATA_NUMBER/2),.ASCEND(ASCEND))stage_1(.clk(clk),.rst_n(rst_n),.data_unsort(data_sorted_stage_2[j*DATA_NUMBER/2*DATA_WIDTH+:DATA_NUMBER/2*DATA_WIDTH]),.label_unsort(label_sorted_stage_2[j*DATA_NUMBER/2*LABEL_WIDTH+:DATA_NUMBER/2*LABEL_WIDTH]),.data_sorted(data_sorted_stage_1[j*DATA_NUMBER/2*DATA_WIDTH+:DATA_NUMBER/2*DATA_WIDTH]),.label_sorted(label_sorted_stage_1[j*DATA_NUMBER/2*LABEL_WIDTH+:DATA_NUMBER/2*LABEL_WIDTH]));    end
endgenerateassign data_sorted = data_sorted_stage_1;
assign label_sorted = label_sorted_stage_1;endmodule

  以次类推,一个八输入的双调排序器可以由4个二输入的双调排序器和2个四输入的双调排序器构成,在这里不一 一列举。
  其次,需要编写构造双调序列部分的RTL代码,由于一个长度N=2的序列,必然是双调序列,所以当序列长度N大于等于4时,才需要进行双调序列的构造,而四输入的双调序列构造器是由一个二输入的升序排序器和一个二输入的降序排序器组合成的,如下。

module input_4_generator
#(parameter DATA_WIDTH = 8,parameter   LABEL_WIDTH = 4,parameter  DATA_NUMBER = 4
)
(clk,rst_n,data_unsort,label_unsort,data_sorted,label_sorted
);input                                 clk;
input                                   rst_n;
input   [DATA_NUMBER*DATA_WIDTH-1:0]    data_unsort;
input   [DATA_NUMBER*LABEL_WIDTH-1:0]   label_unsort;output [DATA_NUMBER*DATA_WIDTH-1:0]    data_sorted;
output  [DATA_NUMBER*LABEL_WIDTH-1:0]   label_sorted;// 二输入升序排序器
input_2_sequencer
#(.DATA_WIDTH(DATA_WIDTH),.LABEL_WIDTH(LABEL_WIDTH),.DATA_NUMBER(2),.ASCEND(1'b1) //升序
)
input_2_sequencer_ascend
(.clk(clk),.rst_n(rst_n),.data_unsort(data_unsort[0*DATA_NUMBER/2*DATA_WIDTH+:DATA_NUMBER/2*DATA_WIDTH]),.label_unsort(label_unsort[0*DATA_NUMBER/2*LABEL_WIDTH+:DATA_NUMBER/2*LABEL_WIDTH]),.data_sorted(data_sorted[0*DATA_NUMBER/2*DATA_WIDTH+:DATA_NUMBER/2*DATA_WIDTH]),.label_sorted(label_sorted[0*DATA_NUMBER/2*LABEL_WIDTH+:DATA_NUMBER/2*LABEL_WIDTH])
);// 二输入降序排序器
input_2_sequencer
#(.DATA_WIDTH(DATA_WIDTH),.LABEL_WIDTH(LABEL_WIDTH),.DATA_NUMBER(2),.ASCEND(1'b0) //降序
)
input_2_sequencer_decend
(.clk(clk),.rst_n(rst_n),.data_unsort(data_unsort[1*DATA_NUMBER/2*DATA_WIDTH+:DATA_NUMBER/2*DATA_WIDTH]),.label_unsort(label_unsort[1*DATA_NUMBER/2*LABEL_WIDTH+:DATA_NUMBER/2*LABEL_WIDTH]),.data_sorted(data_sorted[1*DATA_NUMBER/2*DATA_WIDTH+:DATA_NUMBER/2*DATA_WIDTH]),.label_sorted(label_sorted[1*DATA_NUMBER/2*LABEL_WIDTH+:DATA_NUMBER/2*LABEL_WIDTH])
);endmodule

  而一个八输入的双调序列构造器是由两个四输入的双调序列构造器、一个四输入的双调序列升序排序器和一个四输入的双调降序排序器构成的,如下。

module input_8_generator
#(parameter DATA_WIDTH = 8,parameter   LABEL_WIDTH = 4,parameter  DATA_NUMBER = 8
)
(clk,rst_n,data_unsort,label_unsort,data_sorted,label_sorted
);input                                 clk;
input                                   rst_n;
input   [DATA_NUMBER*DATA_WIDTH-1:0]    data_unsort;
input   [DATA_NUMBER*LABEL_WIDTH-1:0]   label_unsort;output [DATA_NUMBER*DATA_WIDTH-1:0]    data_sorted;
output  [DATA_NUMBER*LABEL_WIDTH-1:0]   label_sorted;wire   [DATA_NUMBER*DATA_WIDTH-1:0]    data_sorted_stage_1;
wire    [DATA_NUMBER*LABEL_WIDTH-1:0]   label_sorted_stage_1;
genvar i;// N/4个四输入双调序列构造器
generatefor(i=0;i<DATA_NUMBER/4;i=i+1) begininput_4_generator#(.DATA_WIDTH(DATA_WIDTH),.LABEL_WIDTH(LABEL_WIDTH),.DATA_NUMBER(DATA_NUMBER/2))input_4_generator(.clk(clk),.rst_n(rst_n),.data_unsort(data_unsort[i*4*DATA_WIDTH+:4*DATA_WIDTH]),.label_unsort(label_unsort[i*4*LABEL_WIDTH+:4*LABEL_WIDTH]),.data_sorted(data_sorted_stage_1[i*4*DATA_WIDTH+:4*DATA_WIDTH]),.label_sorted(label_sorted_stage_1[i*4*LABEL_WIDTH+:4*LABEL_WIDTH]));end
endgenerate// 四输入升序双调排序器
input_4_sequencer
#(.DATA_WIDTH(DATA_WIDTH),.LABEL_WIDTH(LABEL_WIDTH),.DATA_NUMBER(DATA_NUMBER/2),.ASCEND(1'b1)
)
input_4_sequencer_ascend
(.clk(clk),.rst_n(rst_n),.data_unsort(data_sorted_stage_1[0*DATA_NUMBER/2*DATA_WIDTH+:DATA_NUMBER/2*DATA_WIDTH]),.label_unsort(label_sorted_stage_1[0*DATA_NUMBER/2*LABEL_WIDTH+:DATA_NUMBER/2*LABEL_WIDTH]),.data_sorted(data_sorted[0*DATA_NUMBER/2*DATA_WIDTH+:DATA_NUMBER/2*DATA_WIDTH]),.label_sorted(label_sorted[0*DATA_NUMBER/2*LABEL_WIDTH+:DATA_NUMBER/2*LABEL_WIDTH])
);// 四输入降序双调排序器
input_4_sequencer
#(.DATA_WIDTH(DATA_WIDTH),.LABEL_WIDTH(LABEL_WIDTH),.DATA_NUMBER(DATA_NUMBER/2),.ASCEND(1'b0)
)
input_4_sequencer_decend
(.clk(clk),.rst_n(rst_n),.data_unsort(data_sorted_stage_1[1*DATA_NUMBER/2*DATA_WIDTH+:DATA_NUMBER/2*DATA_WIDTH]),.label_unsort(label_sorted_stage_1[1*DATA_NUMBER/2*LABEL_WIDTH+:DATA_NUMBER/2*LABEL_WIDTH]),.data_sorted(data_sorted[1*DATA_NUMBER/2*DATA_WIDTH+:DATA_NUMBER/2*DATA_WIDTH]),.label_sorted(label_sorted[1*DATA_NUMBER/2*LABEL_WIDTH+:DATA_NUMBER/2*LABEL_WIDTH])
);endmodule

四、Test_bench

  最后,我们可以根据需要排序的序列长度编写一个简单的仿真文件,在这里我们以序列长度N=8为例,如下。

`timescale 1ns/1ns
module tb_bitonic_sort();parameter  DATA_WIDTH = 8;
parameter   DATA_NUMBER = 8;
parameter   LABEL_WIDTH = $clog2(DATA_NUMBER);
parameter   ASCEND = 1;    reg clk,rst_n;
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];initial beginclk <= 1'b1;rst_n <= 1'b1;data_unsort[0] <= 9;data_unsort[1] <= 3;data_unsort[2] <= 10;data_unsort[3] <= 15;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;endalways #10 clk <= ~clk;bitonic_sort_top#(.DATA_WIDTH(DATA_WIDTH),.LABEL_WIDTH(LABEL_WIDTH),.DATA_NUMBER(DATA_NUMBER),.ASCEND(ASCEND))bitonic_sort_top(.clk(clk),.rst_n(rst_n),.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]}));endmodule

五、仿真结果

  仿真结果如下图所示,可见总共花费了6个时钟周期,其中,构造双调序列花费了3个时钟周期,而进行双调排序花费了3个时钟周期。输入的未排序的序列为: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,与我们预期的排序结果一致,仿真通过。

六、写在后面

  在本文中,学习了双调排序(Bitonic Sort)的一些基本概念和原理,编写了双调排序算法的RTL代码,并进行了仿真。
  对于一个序列长度为N的双调排序的过程,主要由两个部分组成:(1)构造双调序列;(2)双调排序。那么,在这个过程中,构造双调序列使用了 ∑ i = 0 log ⁡ 2 ( N ) − 2 2 i ∗ ( N / 2 ) \sum\limits_{i = 0}^{{{\log }_2}(N) - 2} {{2^i}} *(N/2) i=0∑log2​(N)−2​2i∗(N/2)个二输入的比较器,而进行双调排序使用了 log ⁡ 2 ( N ) ∗ ( N / 2 ) {\log _2}(N)*(N/2) log2​(N)∗(N/2)个二输入的比较器,总共时钟消耗为 ∑ i = 0 log ⁡ 2 ( N ) − 2 2 i + log ⁡ 2 ( N ) \sum\limits_{i = 0}^{{{\log }_2}(N) - 2} {{2^i}} + {\log _2}(N) i=0∑log2​(N)−2​2i+log2​(N)。
  好了,上面就是关于FPGA中实现双调排序的一些学习笔记,如果有疑义的地方欢迎评论区友好探讨学习!!!!!(FPGA双调排序Verilog代码)

FPGA设计篇之双调排序相关推荐

  1. FPGA设计篇之并行全排序

    FPGA设计篇之并行全排序 写在前面 并行全排序算法原理 并行全排序算法RTL实现 Test_Bench 仿真结果 写在最后 写在前面   在FPGA设计的过程中,有时候需要对一些数据进行排序,那么常 ...

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

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

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

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

  4. C#算法设计排序篇之06-堆排序(附带动画演示程序)

    堆排序(Heap Sort) 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/685 访问. 堆排序是指利用堆积树(堆)这 ...

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

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

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

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

  7. 荐读:FPGA设计经验之图像处理

    荐读:FPGA设计经验之图像处理 今天和大侠简单聊一聊基于FPGA的图像处理,之前也和各位大侠聊过相关的图像处理,这里面也超链接了几篇,具体如下: 图像边缘检测算法体验步骤(Photoshop,Mat ...

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

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

  9. 算法 - 并行排序算法之双调排序(Bitonic_Sort)

    目录 引言: 了解: 什么是并行计算: 并行计算分为时间上并行和空间上并行: 并行排序算法与双调排序之间的关系: 学习: 双调排序(Bitonic_Sort)的介绍及原理: 双调排序中的双调序列: 贝 ...

最新文章

  1. python数据科学和机器学习常用库的官方文档
  2. 对Linux系统中的时钟和时间的探讨
  3. java clone 序列化_关于Java对象深度Clone以及序列化与反序列化的使用
  4. HTML DOM之标签操作方法
  5. ajaxGet 获取封装
  6. java file list listfiles,Java File listFiles()用法及代码示例
  7. 【系列4】使用Dockerfile创建带tomcat的Centos Docker镜像
  8. 身份证前6位对应的省市区县
  9. java计算机毕业设计南京新东方学校家校通系统源码+程序+lw文档+mysql数据库
  10. CPU卡指令文件读取算法
  11. access如何设置定期报表汇总_Access如何制作复杂报表
  12. iOS 通讯录备份、恢复
  13. 云课堂软件工程(C编码实践篇)学习之我见
  14. windows server 2008服务器管理器,添加IIS配置(2012同理)
  15. 算法导论 直接寻址表
  16. 安装golang出现 Hey! The program ‘go‘ is currently not installed. You can install it by typing...
  17. 科技爱好者周刊(第 159 期):游戏开发者的年薪
  18. android ims注册流程,ims注册流程volte通话流程总结
  19. android 三星 安全,三星手机可以升级到Android 7.0,新老用户都必须看一下
  20. Flink任务报:Could not allocate the required slot within slot request timeout.

热门文章

  1. 数学国际大师 数学奖项大满贯得主 丘成桐老师 访谈video
  2. 语音识别 CTC Loss
  3. Vector3.Angle
  4. Coinbase为热门电子商务平台推出加密货币插件
  5. 放大格局,放小自己 |【常垒·常识】
  6. PCIe扫盲——链路初始化与训练基础(三)之LTSSM
  7. 杰理AC692N---sdk_tool工具的使用(蓝牙参数修改)
  8. docker desktop使用教程(一)
  9. 第7篇:SELECT条件查询
  10. android 光晕效果,【转】七、android图片特效处理之光晕效果