当前位置:   article > 正文

Verilog手撕代码(11)1检测(统计个数、独热码检测、1的位置检测)_独热码 verilog

独热码 verilog

统计1的个数

module test(
	input [7:0]data_in,
	input [3:0]out
);
reg [3:0]cnt;
integer i;
always@(data_in)begin
	cnt <= 'd0;
	for(i = 0;i < 8;i = i + 1)begin
		if(data_in[i])
			cnt <= cnt + 1'b1;
		else 
			cnt <= cnt;		
	end
end
assign out = cnt;
//写法二
//assign out = data_in[0] + data_in[1] + data_in[2] + data_in[3] + data_in[4] + data_in[5] + data_in[6] + data_in[7]; 
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

Testbench:

`timescale 1ns/1ns
module test_tb;

	reg [7:0]data_in;
	wire [3:0]out;
	
	test test_inst(
		.data_in		(data_in	),
		.out			(out		)
);	
	initial begin
		data_in = 8'b0000_0000;
		#200;
		data_in = 8'b1111_0010;
		#200;
		data_in = 8'b1100_0010;
		#200;
		data_in = 8'b1111_1111;
		#200;
		$stop;
	
	end	
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

仿真结果:
在这里插入图片描述

独热码检测

独热码

独热码是一种二进制编码方式,它的特点是,用来编码这个数的N位bit中,有且只有一位是1,其余位全部为0。因为只有1位是1,所以叫做one-hot (对应的,还有一种编码方式是只有1位是0,其余位都是1,叫做one-cold)

状态机中使用独热码的好处

利用one-hot来编码状态机,好处就是一个flop就表示一个状态,用来判断状态机在哪一个状态的时候就只需要看第几个flop为1即可,而不需要像binary编码那样是所有flop在一起参与比较。这样可以省下一点点逻辑的比较电路的延时,代价显而易见,用one-hot编码状态机需要的寄存器比binary编码要多,这就是一个典型的利用面积换性能的trade off。

方法一:公式法/卡诺图

00011110
000101
011000
110000
101000
Y = (A[0] & (!A[1]) & (!A[2]) & (!A[3])) 
   |((!A[0]) & A[1] & (!A[2]) & (!A[3]))
   |((!A[0]) & (!A[1]) & A[2] & (!A[3]))
   |((!A[0]) & (!A[1]) & (!A[2]) & A[3]);
  • 1
  • 2
  • 3
  • 4

方法二:for循环

其实有个很简单的思路,就是从独热码的定义出发:只有一位是1,其余位都是0。那么不管我输入信号有多少位,有一个性质是不变的 – 把这些位各自相加,最后的结果肯定得是1。那么我们就可以利用一个for循环,把每一位相加,最后再把最终的结果和1比较一下,如果是1,那就是独热码,如果不是1,那就是其他的数

module test_1(
	input [3:0]data_in,
	input out
);
integer i;
reg [3:0]sum
always@(*)begin
	sum <= 'd0;
	for(i = 0;i < 4; i = i + 1)begin
		sum <= sum + data_in[i];
	end	
end
assign out = sum == 1?1'b1:1'b0;
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

system verilog代码:

function automatic logic is_onehot(input [WIDTH-1:0] sig);
  logic [WIDTH-1:0] parity;
  parity[0] = sig[0];
  for(int i = 1; i < WIDTH; i++)
     parity[i] = parity[i-1] ^ sig[i];
  is_onehot = parity[i-1] & (&(parity | ~sig));
endfunction
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

SUM_WIDTH要用$clog2之后再加1,为什么呢?因为加入输入为4位信号,如果SUM_WIDTH要用clog2之后不加1的话,SUM_WIDTH的位宽为2bit,最大表达为11(3),而4位信号全为1时,sum应该为4,表达位宽不够。

方法三:奇偶校验

对于一个4位的二进制数,我们对这4位奇偶校验,利用异或门依次进行每一位,最后的结果如果是奇数个1那么4位异或之后结果就是1,如果偶数个1那么结果就是0。看到了吗,我们要找的独热码其实是奇数个1的特殊情况,即只有1位是1。所以更加巧妙的方法就来自于这个按位异或。

把A相应按位XOR的结果记为P,其中P[0] = A[0], P[i] = A[i] ^ P[i-1]
在这里插入图片描述
即对于独热码,我们得到的P会是这样一个数:如果独热码A的第i位为1,那么P的第i-1到第0位都是0,而第i位和更高位都是1。注意,这个规律只对独热码适用,大家可以试验一下其他任何数,只要多于1位是1,那么就不会出现高位连续的都是1,高位必然会出现0。

将A按位取反,然后再和P按位OR起来会得到什么?A既然是独热码,那么除了为1的那一位(假设是第i位),取反之后都会变成1,只有第i位会是0。而P的第i位是1,那么最后按位OR的结果是什么?全部每一位都是1。

那么如果A不是独热码,而是有两个1或者更多1,假设第i位和第k位是1(k是i之后第一个1),我们进行上面的操作会得到什么?P[k]会得到0。A反和P按位OR之后第k位也是0.

一个特殊情况,即A为全0。当A为全0的时候,P也是全0,但是A取反之后是全1,所以A反和P按位OR之后也会得到全1。幸好,特殊情况就只有这一种,我们只需要对A进行一下全0判断就可以了。

system verilog代码:

function automatic logic is_onehot(input [WIDTH-1:0] sig);
  logic [WIDTH-1:0] parity;
  parity[0] = sig[0];
  for(int i = 1; i < WIDTH; i++)
     parity[i] = parity[i-1] ^ sig[i];
  is_onehot = parity[i-1] & (&(parity | ~sig));
endfunction
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

向量前导1检测器

设计一个组合逻辑电路,检测输入32位0/1向量中从高到低第一个1出现的位置,如果向量为全0则输出32。例如:

输入00011000 10000000 00000000 00000000,输出3;

输入00000000 11111111 00000000 00000000,输出8;

输入00000000 00000000 00000000 00001010,输出28.

即输出从左向右,出现第一个1的位置

casex、cazez

module seq_head_detect(
	input 	[31:0]	data_in,
	output 	    	pos_out
);
 
reg [31:0] tmp;
reg [5:0]  pos_out_tmp;
reg [5:0]  pos_out;
 
always @(*) begin
 
	tmp = data_in;
	
	casex(tmp)
	
		32'b1xxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd0;
		32'b01xx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd1;
		32'b001x_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd2;
		32'b0001_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd3;	//第4位为1
		32'b0000_1xxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd4;
		32'b0000_01xx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd5;
		32'b0000_001x_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd6;
		32'b0000_0001_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd7;	//8
		32'b0000_0000_1xxx_xxxx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd8;
		32'b0000_0000_01xx_xxxx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd9;
		32'b0000_0000_001x_xxxx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd10;
		32'b0000_0000_0001_xxxx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd11;	//12
		32'b0000_0000_0000_1xxx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd12;
		32'b0000_0000_0000_01xx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd13;
		32'b0000_0000_0000_001x_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd14;
		32'b0000_0000_0000_0001_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd15;	//16
		32'b0000_0000_0000_0000_1xxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd16;
		32'b0000_0000_0000_0000_01xx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd17;
		32'b0000_0000_0000_0000_001x_xxxx_xxxx_xxxx : pos_out_tmp = 6'd18;
		32'b0000_0000_0000_0000_0001_xxxx_xxxx_xxxx : pos_out_tmp = 6'd19;	//20
		32'b0000_0000_0000_0000_0000_1xxx_xxxx_xxxx : pos_out_tmp = 6'd20;
		32'b0000_0000_0000_0000_0000_01xx_xxxx_xxxx : pos_out_tmp = 6'd21;
		32'b0000_0000_0000_0000_0000_001x_xxxx_xxxx : pos_out_tmp = 6'd22;
		32'b0000_0000_0000_0000_0000_0001_xxxx_xxxx : pos_out_tmp = 6'd23;	//24
		32'b0000_0000_0000_0000_0000_0000_1xxx_xxxx : pos_out_tmp = 6'd24;
		32'b0000_0000_0000_0000_0000_0000_01xx_xxxx : pos_out_tmp = 6'd25;
		32'b0000_0000_0000_0000_0000_0000_001x_xxxx : pos_out_tmp = 6'd26;
		32'b0000_0000_0000_0000_0000_0000_0001_xxxx : pos_out_tmp = 6'd27;	//28
		32'b0000_0000_0000_0000_0000_0000_0000_1xxx : pos_out_tmp = 6'd28;
		32'b0000_0000_0000_0000_0000_0000_0000_01xx : pos_out_tmp = 6'd29;
		32'b0000_0000_0000_0000_0000_0000_0000_001x : pos_out_tmp = 6'd30;
		32'b0000_0000_0000_0000_0000_0000_0000_0001 : pos_out_tmp = 6'd31;	//32
		default 									: pos_out_tmp = 6'd32;	//全0
		
	endcase                                          
	pos_out = pos_out_tmp;
end
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

逐项比较if……esle

module seq_head_detect(
	input 	[31:0]	data_in,
	output 	        pos_out
);
 
reg [31:0] tmp;
reg [5:0]  pos_out_tmp;
reg [5:0]  pos_out;
 
always @(*) begin
 
	tmp = data_in;
	
	if(tmp[31]) pos_out_tmp = 6'd0;
	else if(tmp[30]) pos_out_tmp = 6'd1;
	else if(tmp[29]) pos_out_tmp = 6'd2;
	else if(tmp[28]) pos_out_tmp = 6'd3;
	else if(tmp[27]) pos_out_tmp = 6'd4;
	else if(tmp[26]) pos_out_tmp = 6'd5;
	else if(tmp[25]) pos_out_tmp = 6'd6;
	else if(tmp[24]) pos_out_tmp = 6'd7;
	else if(tmp[23]) pos_out_tmp = 6'd8;
	else if(tmp[22]) pos_out_tmp = 6'd9;
	else if(tmp[21]) pos_out_tmp = 6'd10;
	else if(tmp[20]) pos_out_tmp = 6'd11;
	else if(tmp[19]) pos_out_tmp = 6'd12;
	else if(tmp[18]) pos_out_tmp = 6'd13;
	else if(tmp[17]) pos_out_tmp = 6'd14;
	else if(tmp[16]) pos_out_tmp = 6'd15;
	else if(tmp[15]) pos_out_tmp = 6'd16;
	else if(tmp[14]) pos_out_tmp = 6'd17;
	else if(tmp[13]) pos_out_tmp = 6'd18;
	else if(tmp[12]) pos_out_tmp = 6'd19;
	else if(tmp[11]) pos_out_tmp = 6'd20;
	else if(tmp[10]) pos_out_tmp = 6'd21;
	else if(tmp[9]) pos_out_tmp = 6'd22;
	else if(tmp[8]) pos_out_tmp = 6'd23;
	else if(tmp[7]) pos_out_tmp = 6'd24;
	else if(tmp[6]) pos_out_tmp = 6'd25;
	else if(tmp[5]) pos_out_tmp = 6'd26;
	else if(tmp[4]) pos_out_tmp = 6'd27;
	else if(tmp[3]) pos_out_tmp = 6'd28;
	else if(tmp[2]) pos_out_tmp = 6'd29;
	else if(tmp[1]) pos_out_tmp = 6'd30;
	else if(tmp[0]) pos_out_tmp = 6'd31;
	else			pos_out_tmp = 6'd32;
	pos_out = pos_out_tmp;
end
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

二分法

module seq_head_detect(
	input 	[31:0]	data_in,
	output 	[ 5:0]	pos_out
);
 
//mark:assign不能给reg赋值,只能赋给wire
wire [4:0]  data_chk;
wire [15:0] data_1;	
wire [7:0]  data_2;
wire [3:0]  data_3;
wire [1:0]  data_4;
 
 
assign data_chk[4] = |data_in[31:16];//高16位相或,依此类推
assign data_chk[3] = |data_1[15:8];
assign data_chk[2] = |data_2[7:4];
assign data_chk[1] = |data_3[3:2];
assign data_chk[0] = |data_4[1]; 
 
assign	data_1	= (data_chk[4]) ? data_in[31:16] : data_in[15:0]; //若data_in高16位有1,则data1取其高16位,否则取低16位
assign	data_2 	= (data_chk[3]) ? data_1[15:8] 	: data_1[7:0];		//若data_1高8位有1,则data2取其高8位,否则取低8位
assign	data_3 	= (data_chk[2]) ? data_2[7:4] : data_2[3:0];		//若data_2高4位有1,则data3取其高4位,否则取低4位
assign	data_4 	= (data_chk[1]) ? data_3[3:2] : data_3[1:0];		//若data_3高2位有1,则data4取其高2位,否则取低2位
assign 	pos_out = (|data_in) ? {1'b0, ~data_chk} : 6'd32;	//若data_in为全0,posout = 6'd32
/*data_in中有1时,用低5位表示足够,则最高位为0*/
/*假定data_in首位为1,则data_chk = 11111,应有pos_out = 00000,类推可知data_chk取反*/
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

Testbench:

`timescale 1ns / 1ps
 
module tb_seq_head_detect();
reg [31:0] data_in;
wire [5:0] pos_out;
 
initial begin
	data_in = 32'b0000_0000_0000_0000_0000_0000_0000_0000;
	#100
	data_in = 32'b0000_0001_0000_0000_0000_0000_0000_1101;//第8位,pos_out = 7
	#100
	data_in = 32'b0000_0000_0000_0000_0010_0000_0000_1101;//第19位,pos_out = 18
end
seq_head_detect u_seq_head_detect(
	.data_in (data_in),
	.pos_out (pos_out)
);
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

仿真结果:
在这里插入图片描述

找出高位或低位第一个出现1

module find_first
#(
    parameter WIDTH = 6
)(
    input [WIDTH-1:0] req,
    output [WIDTH-1:0] grant
);
genvar i; 

if(lsb_first)
    begin:lsb_to_msb
        assign grant[0] = req[0];
        for(i=1;i<WIDTH;i=i+1)begin
            grant[i] = req[i] & ~|grant[i-1:0];
        end    
    end
else if(!lsb_first)
    begin:msb_to_lsb
        assign grant[WIDTH-1] = req[WIDTH-1];
        for(i=WIDTH-2;i>0;i=i-1)begin
            grant[i] = req[i] & ~|grant[WIDTH-1:i+1];
        end
    end
 
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号