寻找第一个1
输入一个向量,如何从LSB或者MSB或者反过来找出第一个出现1的位置并生成独热码?这个问题碰到好多次了,今天总结一下。
这个电路有点类似于一个优先编码器(所以该电路就是固定优先级的仲裁器),例如对于一个4bit位宽的向量来说,其真值表如下
| Input | Output |
|---|---|
| 0001 | 0001 |
| xx10 | 0010 |
| x100 | 0100 |
| 1000 | 1000 |
上述真值表的Verilog电路实现如下
module OneHot(
input [3:0] din,
output [3:0] onehot
);
reg [3:0] onehot_w;
always@(*)begin
casex(din)
4'b0001:onehot_w = 4'b0001;
4'b001x:onehot_w = 4'b0010;
4'b01xx:onehot_w = 4'b0100;
4'b1000:onehot_w = 4'b1000;
endcase
end
assign onehot = onehot_w;
endmodule
第二种方法是一个比较巧妙的方法,并且进行参数化实现也比较方便。首先有这样一种求一个数的补码的方法:从LSB到MSB,找到第一个为1的位置,该位保持不变,之后一直到MSB所有的位都取反,即可得到该数的补码。稍加思索就可以发现,既然可以用这种方法找到补码,那换句话说补码就一定符合这个规则,那么补码就可以作为mask来找到第一个1出现的地方了:因为补码是从第一个1之后所有的位都取反,那么将原数与补码按位与,就得到了一个独热码,并且该独热码1出现的位置就是原数第一个1出现的位置。
module onehot#(
parameter WIDTH = 8
)(
input [WIDTH-1:0] din,
output [WIDTH-1:0] onehot
);
wire [WIDTH-1:0] complement_w = ~(din-1);
assign onehot = din&complement_w;
endmodule
再添加一个参数用于调整寻找的方向,最终的设计如下
module onehot#(
parameter WIDTH = 8,
parameter DIRECTION = 0
)(
input [WIDTH-1:0] din,
output [WIDTH-1:0] dout
);
wire [WIDTH-1:0] din_w;
wire [WIDTH-1:0] dout_w;
genvar i;
generate
for(i=0;i<WIDTH;i=i+1)begin
if(DIRECTION==0)begin:gen_lsb_msb
assign din_w[i] = din[i];
assign dout[i] = dout_w[i];
end
else begin:gen_msb_lsb
assign din_w[i] = din[WIDTH-1-i];
assign dout[i] = dout_w[WIDTH-1-i];
end
end
endgenerate
wire [WIDTH-1:0] complement_w = ~(din_w-1);
assign dout_w = din_w&complement_w;
endmodule
浙公网安备 33010602011771号