马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?注册
x
本文所用的算法很简单,以升序来说,有一数列[A0…..An],分别比较相邻的两两个元素,如果A(n) > A(n+1),则交换两个数的位置 举个例子:排序 序列[ 4 3 2 1]第一次比较分组{A0–A1};{A2–A3}: {4 > 3};{2>1}第一次交换位置后[ 3 4 1 2]第二次比较分组{A0};{A1-A2};{A3}:{3};{4>1};{2}
当然不能和第一次一样分组,那样就是原地踏步第二次交换位置后[ 3 1 4 2 ]第三次比较分组{A0–A1};{A2–A3}:{3 > 1};{4 > 2}
其实是和第一次一样,这个很重要,意味着可以用迭代的方法第三次交换位置后[1 3 2 4]第四次比较分组{A0};{A1-A2};{A3}:{1};{3>2};{4}
和第二次一样第四次交换位置后[ 1 2 3 4 ]排序完成算法需要4个clock,对4个,不是8个。
此算法处理N长度的序列就需要N个clock,序列元素可以同值。
上面所有的“两两“交换也是http://opencores.org/的实现方式。
我要用更激进的方法~~”四四“分组,组内一次排4个数。序列[A0,A1,A2,A3…….A(n-2),A(n-1),A(n)]第一次分组{A1,A2,A3,A4};{A5->A8}…..{A(n-3),A(n-2),A(n-1),A(n)};第二次分组{A1-A2};{A3,A4,A5,A6}…..{A(n-5)->A(n-2};{A(n-1),A(n)};循环第一第二次。此方法有个缺点,会有冗余的比较,例如第二次分组的时候A3,A4顺序是已经排过的,但是没关系,并不影响结果。
实现思路: 4个数分组排序是核心,如何实现4个数分组排序呢,且要在尽可能少的clock内完成,最好只用一个clock,如果用4个clock,就和上面的方式一样了。
假设排序前的序列是[A0,A1,A2,A3] ,排好序后的序列是[B0,B1,B2,B3]
A序列两两比较( >= :大于或等于),共有6种结果,我们把结果用一个的向量wire[5:0] C表示便是 6‘bXXX_XXX(本人使用的是verilog)
- C[5] = A0>=A1;
- C[4] = A0>=A2;
- C[3] = A0>=A3;
- C[2] = A1>=A2;
- C[1] = A1>=A3;
- C[0] = A2>=A3;
复制代码
那么,B的排序应该就是由C决定的 B=F(C);
B的值又是怎么决定的呢?
1、B[0] 如果A种的某个元素Ax不小于其他3个,那么我们就可以把它存入B[0]中。如果A0>{A1,A2,A3},那么就把A0赋予B0,
verilog实现:
- always@(posedge clock)begin
- casex(C)
- 6’b111_xxx: B[0]<= A[0];
- 6’b0xx_11x: B[0]<= A[1];
- 6’bx0x_0x1: B[0]<= A[2];
- 6’bxx0_x00: B[0]<= A[3];
- default: B[0]<= A[0];
- endcase
- end
复制代码
为什么case 有些状态有0?
对于A[0]来说 它比其他三个数大即 6‘b111_xxxx:
但是对于A[1] ,他要是最大必须是 6’b0xx_11x; C[5] 对于的是A[0] >= A[1], “0” 表示此式子不成立!
2、B[3] 和B[0] 类似,就不细说了
3、B[1],B[2] B[1]:Ax对其他3个数中,比一个小,比两个大
B[2]:Ax对其他3个数中,比两个小,比一个大
情况比上两种复杂
- always@(posedge clock)begin
- casex(C)
- 6’b011_xxx,6’b101_xxx,6’b110_xxx: B[1]<= A[0]; //D0-01-d1 D0-01-d2 D0-01-d3
- 6’b1xx_11x,6’b0xx_01x,6’b0xx_10x: B[1]<= A[1]; //d0-01-D1 D1-01-d2 D1-01-d3
- 6’bx1x_0x1,6’bx0x_1x1,6’bx0x_0x0: B[1]<= A[2]; //d0-01-D2 d1-01-D2 D2-01-d3
- 6’bxx1_x00,6’bxx0_x10,6’bxx0_x01: B[1]<= A[3]; //d0-01-D3 d1-01-D3 d2-01-D3
- default: B[1]<= A[0];
- endcase
- end
- always@(posedge clock)begin
- casex(C)
- 6’b001_xxx,6’b100_xxx,6’b010_xxx: B[2]<= A[0]; //D0-01-d1 D0-01-d2 D0-01-d3
- 6’b1xx_01x,6’b0xx_00x,6’b1xx_10x: B[2]<= A[1]; //d0-01-D1 D1-01-d2 D1-01-d3
- 6’bx1x_1x1,6’bx0x_1x0,6’bx1x_0x0: B[2]<= A[2]; //d0-01-D2 d1-01-D2 D2-01-d3
- 6’bxx1_x10,6’bxx0_x11,6’bxx1_x01: B[2]<= A[3]; //d0-01-D3 d1-01-D3 d2-01-D3
- default: B[2]<= A[0];
- endcase
- end
复制代码 OK,”四四说完了“ 组装N个序列了。 组装一个25的看看,为什么是25,25不仅不是偶数,更不是4的倍数。haha~,25是5x5,排序25,就是直接做了一个5x5的中值滤波器!
25的分组,用6个“四”的排序,余1就不比较了,github上我是有用“三”的排序。 奇数次分组{A0->A3} {A4->A7} {A8->A11} {A12-A15} {A16->A19} {A20->A23} {A24}偶数次分组{A0} {A1} {A2->A5} {A6->A9} {A10->A13} {A14->A17} {A18->A21} {A22-A24}只要迭代6次(github上的可不是迭代,纯流水实现),共排序13次(因为不够4除)就能实现25的排序,比传统方法快一倍,流水资源自然少一半。 FINISH:既然多个数分组排序能提高速度和资源,为什么选4个而不是8个,16个呢,这样不是更快吗?
是的,组内数越多,迭代次数越少
如果把[A0…An] 只做成一个组,那么只要一个clock就行了。
时序,数越多,路径延时越长 排4的时候是
case((3_+2+1)’bxxxxxx) 排8的时候就是
case((7+6+5+4+2+1)’dx)=(case(sum(#8))= case(25’dx)
2^6 = 64种情况 排25的时候
2^25 = 33554432 放弃吧 源代码下载链接
|