【Code Review】Onehot2Bin

文章介绍了在工程实践中遇到的onehot2bin模块,该模块用于从onehot编码中找到1的位置。通过参数化设计和高位补0处理,实现了将任意长度的onehot编码转换为对应的bin_num。关键在于利用奇偶性,通过两层循环和位运算找出onehot编码中的1,从而生成bin_num。该模块的实现思路体现了硬件设计中的反向思维和组合逻辑应用。
摘要由CSDN通过智能技术生成

最近在工程实践中用到了onehot2bin这个模块,发现它的写法和直观上的理解有一点差距,并不是很好理解,有必要记录一下。

首先要提出我们的需求:给定一个任意长度的onehot编码,也就是只有1bit为1的一串二进制数,如何用组合逻辑找到这个硕果仅存的1的位置?

本着尽可能提高代码重用性的精神,我们创建一个参数化的模块:

module onehot2bin #(
    parameter WIDTH  = 8,
    parameter BIN_WD = $clog2(WIDTH)
)(
    input  [WIDTH-1:0]  onehot_num,
    output [BIN_WD-1:0] bin_num
);

endmodule

因为WIDTH有可能并不等于2^n,这会导致后面的处理比较难受,所以我们很自然地要去把这个onehot_num高位补齐到2^n个bit:

// power_two function
function integer power_two;
    input integer number; begin
        power_two = (number <= 0) ? 1 : 2 << (number - 1);
    end
endfunction

localparam TRUE_ONEHOT_WD = power_two(BIN_WD);

wire [TRUE_ONEHOT_WD-1:0] true_onehot_num;

assign true_onehot_num = {TRUE_ONEHOT_WD{1'b0}} | onehot_num;

这里的true_onehot_num就是高位补0之后的onehot_num,接下来就是产生bin_num的功能逻辑了,乍一看简直是一段magic code:

wire [TRUE_ONEHOT_WD-1:0] or_bit [BIN_WD-1:0];

generate
genvar i, j;
for(i = 0; i < BIN_WD; i = i + 1) begin : loop_1
    for(j = 0; j < TRUE_ONEHOT_WD; j = j + 1) begin : loop_2
        if((j % power_two(i+1)) < power_two(i))
            assign or_bit[i][j] = true_onehot_num[j];
        else
            assign or_bit[i][j] = 1'b0;
    end
    assign bin_num[i] = ~|(or_bit[i]);
end

唯象地看,bin_num的每个bit为1,表示对应的一行or_bit(长度和onehot码相同)全为0,而每一行or_bit都在固定位置存在一些0,其他位置则是在寻找onehot码的那个1,wtf?

个人理解,这段代码难懂之处在于它是从bin_num的每个bit出发,倒推它们的组合逻辑,这是纯硬件思想,和我们惯常的正向思考是相悖的(毕竟谁会首先想到自己拎起自己)。

为了简便,我们先假设WIDTH = 8,BIN_WD = 3,来分析一下每一层循环都做了什么事情:

i = ?if判断条件

or_bit检查onehot

的位置

or_bit固定为0

的位置

or_bit全0的含义
0j % 2 < 10, 2, 4, 61, 3, 5, 7bin_num是奇数
1j % 4 < 20, 1, 4, 52, 3, 6, 7bin_num包含奇数个2
2j % 8 < 40, 1, 2, 34, 5, 6, 7bin_num包含奇数个4

这样看起来就很清楚了,这个模块相当于把bin_num的每个bit理解为1/2/4个数的奇偶性,例如bin_num = 6  = 0*1 + 1*2 + 1*4 = 3‘b110,也就是每个bit的在二进制当中的本来含义,完整代码如下:

module onehot2bin #(
    parameter WIDTH  = 8,
    parameter BIN_WD = $clog2(WIDTH)
)(
    input  [WIDTH-1:0]  onehot_num,
    output [BIN_WD-1:0] bin_num
);

// power_two function
function integer power_two;
    input integer number; begin
        power_two = (number <= 0) ? 1 : 2 << (number - 1);
    end
endfunction
localparam TRUE_ONEHOT_WD = power_two(BIN_WD);

genvar i, j;
wire [TRUE_ONEHOT_WD-1:0] true_onehot_num;
wire [TRUE_ONEHOT_WD-1:0] or_bit [BIN_WD-1:0];

assign true_onehot_num = {TRUE_ONEHOT_WD{1'b0}} | onehot_num;

generate
for(i = 0; i < BIN_WD; i = i + 1) begin : loop_1
    for(j = 0; j < TRUE_ONEHOT_WD; j = j + 1) begin : loop_2
        if((j % power_two(i+1)) < power_two(i))
            assign or_bit[i][j] = true_onehot_num[j];
        else
            assign or_bit[i][j] = 1'b0;
    end
endgenerate

endmodule

日拱一卒,今天又是有收获的一天。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值