onehot编码检测中的FPGA设计思考

  ‘’16bits位宽寄存器,用五(六也行)级逻辑判断其中有15个0和1个1‘’,这么道题目,面试无数,几乎没有人能答出来,连给我衍生‘’14个0和2个1‘’的机会都没有。

  今天的问题来源于知乎,某大牛说的面试题,据说很少有人给出正确答案。正确答案究竟是什么我也不清楚,我的目标是实现一个FPGA的版本,特记录于此。

  说明一下问题,一个16bits的数输入,检查其中1的个数,如果为独热码,即16位中只有1位为1,则输出为1。题目乍看起来很简单,使用Verilog,可以很轻松实现,实现方法不在赘述。出此面试题的人应该也不是考察HDL编码能力,而是考察面试者对底层逻辑的理解,出题人的本意应该是希望使用逻辑门来实现此功能,但本人是个FPGA工程师,就应该遵循FPGA的设计理念,所以决定使用LUT实现该功能。LUT为xilinx FPGA的原语,LUT是基于SRAM的查找表,使用查找表可以完成逻辑门的功能。如4输入LUT,则是一个4输入,1输出的查找表,查找表的深度为2^4=16,查找表的内容则是逻辑函数的真值表。作为FPGA工程师时刻都要清楚,FPGA的组合逻辑几乎都是用LUT完成的。

  言归正传,Xilinx 7系列的查找表为6输入,少于6输入可以只覆盖查找表的低位地址,多余6输入需要级联组合,这也就是FPGA中的逻辑层数,级联了几级便是几层逻辑层数。分析题目,16个输入,有一个输入为1则结果为True,多余1个或是全为0则False。这里引入另一个FPGA的设计理念,即并行二字,FPGA中的电路可以并行运行,不同功能模块只要没有先后依赖关系就可以并行处理。个人以为这个是FPGA和GPU的最大差别,GPU为单指令多数据SIMD,FPGA则为MIMD。GPU应该还是串行执行指令的,而FPGA的不能功能模块则为不同指令,这些不同指令可以同时执行。关于GPU与FPGA的差别,仅是个人思路整理,没有深刻研究过GPU。

  再继续说检测onehot,检测主要分成三部分,第一输入中只有一位为1则输出1,如0x001,0x002,0x004...2^n等,使用2个6输入LUT,1个4输入LUT,2*6+4=16个输入。6输入LUT真值表为64‘h0000_0001_0001_0116,4输入LUT真值表为16'h0116,每个真值表都能够检出仅存一个1的输入,每个LUT此时能得出的结果是,输出true表示仅有一个1存在,输出Flase表示输入可能有1个以上的1或是全为0,此时三个LUT输出求结果无解。所以还需要引入第二功能,检测全为0的输入,仍然是2个6输入LUT,1个4输入LUT,真值表值为64’d1,16'd1,表示只有0x0地址输出true,即全为0输入,同样有3个输出,此结果可以确定输入全为0,补充了第一步的条件。这两个功能为并行执行,为第一级组合逻辑,共6个输出,这6个输出可以作为函数输入求解。第二级功能使用一个6输入LUT,假设为全为0检测的输出是dout0[2:0],仅有独个1的输出是dout1[2:0],求结果result=dout1[0]&dout0[1]&dout0[2] | dout1[1]&dout0[0]&dout0[2] | dout1[2]&dout0[1]&dout0[0],这个函数正好是个6输入LUT,LUT初始值:INIT 64'hEE80AA80CC808080。前文已述,4输入lut实际使用6输入lut,所以该项目一共用了7个lut,共两层逻辑。

  

 1 module Top(
 2     input[15:0] din,
 3     output dout
 4     );
 5     reg [15:0] dinr;
 6     always@(*)begin
 7         dinr = din;
 8     end
 9     wire [3:0] dl1;
10     wire [3:0] dl0;
11     wire dl2;
12     
13     wire[2:0] xl1;
14     wire[2:0] xl0;
15     genvar x;
16     generate
17         for (x=0;x<12;x=x+6)
18         begin : w1
19             Lut6_ #(.init(64'h0000_0001_0001_0116)) Lut6_inst(
20                .in(din[x+5:x]),
21                .out(xl1[x/6])
22             );
23         end
24     endgenerate
25     Lut4_ #(.init(16'h0116)) Lut4_x(
26                 .in(din[15:12]),
27                 .out(xl1[2])
28                 );
29    
30     genvar y;
31     generate
32         for (y=0;y<12;y=y+6)
33         begin : w0
34             Lut6_ #(.init(64'd1)) Lut6_inst(
35                .in(din[y+5:y]),
36                .out(xl0[y/6])
37             );
38         end
39     endgenerate
40     Lut4_ #(.init(16'd1)) Lut4_y(
41                 .in(din[15:12]),
42                 .out(xl0[2])
43                 );
44    assign dout = xl1[0]&xl0[1]&xl0[2] | xl1[1]&xl0[0]&xl0[2] | xl1[2]&xl0[0]&xl0[1];            
45 
46 endmodule
47 
48 module Lut4_  #(
49     parameter init = 16'h0000
50     ) (
51     input [3:0] in,
52     output out
53     );
54      LUT4 #(
55        .INIT(init)  // Specify LUT Contents
56     ) LUT4_inst (
57        .O(out),   // LUT general output
58        .I0(in[0]), // LUT input
59        .I1(in[1]), // LUT input
60        .I2(in[2]), // LUT input
61        .I3(in[3])  // LUT input
62     );   
63 endmodule
64 
65 module Lut6_  #(
66     parameter init = 64'h0000000000000000
67     ) (
68     input [5:0] in,
69     output out
70     );
71      LUT6 #(
72           .INIT(init)  // Specify LUT Contents
73        ) LUT6_inst (
74           .O(out),   // LUT general output
75           .I0(in[0]), // LUT input
76           .I1(in[1]), // LUT input
77           .I2(in[2]), // LUT input
78           .I3(in[3]), // LUT input
79           .I4(in[4]), // LUT input
80           .I5(in[5])  // LUT input
81        );
82 endmodule
View Code

 

posted @ 2020-07-17 22:03  蘑菇菌团  阅读(607)  评论(0编辑  收藏  举报