Verilog 统计第一个1后0的个数/1的个数/第一个1的位置

一、前言

当数据的位宽不是很长时,此类问题可以使用移位寄存器来解决。我们将输入数据不断的右移,这样每次只需要对最后一bit进行判断。由于需要统计个数,我们还需要定义一些计数器,cnt用来计数已经处理了多个bit,而cnt0和cnt1用来记录要统计的0和1的个数。
当然还需要一些其他逻辑辅助完成这些功能,可以参考下面的代码,为了方便理解,里面也写了一些注释。

二、从低到高统计数据中第一个1后面的0的个数

/*
	从低到高 统计第一个1后面的0的个数
*/
module cnt_num(
	input clk,
	input rst_n,
	input din_en,
	input [7:0]din,
	output reg[3:0]count_out
);

	reg [3:0]cnt;//计数检测了多少bit
    reg [3:0]cnt0;//计数0的个数
	reg flag;//检测到了第一个1
	reg [7:0]din_r;//din的移位寄存器

	reg din_en_r;
	wire pos_din_en;
	localparam BitWidth = 8;

	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			din_en_r <= 1'b0;
		else 
			din_en_r <= din_en;
	end

	assign pos_din_en = din_en && (!din_en_r);

	
	
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			cnt <= 4'd0;
		else if(din_en && (cnt < BitWidth))
			cnt <= cnt + 1'b1;
		else 
			cnt <= 4'd0;
	end

	//当flag有效时,就开始判断每一bit是不是0
	//是的话,cnt0计数+1;否则就保持不变,当所有bit检测完后归零
  	always@(posedge clk or negedge rst_n)begin
		if(!rst_n || pos_din_en)
			cnt0 <= 4'd0;
		else if(flag && (din_r[0] == 0))
			cnt0 <= cnt0 + 1'b1;
		else if (cnt < BitWidth) begin
            cnt0 <= cnt0;
        end
        else
			cnt0 <= 4'd0;
	end
	
	//判断是否已经检测到了第一个1
  	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			flag <= 1'b0;
		else if(din_r[0])
			flag <= 1'b1;
		else if (cnt == BitWidth) begin
            flag <= 1'b0;
        end
        else
            flag <= flag;
			
	end

	//din的右移移位寄存器,这样只需要每次检测最低位即可
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			din_r <= 8'd0;
		else if(pos_din_en)
			din_r <= din;
		else if(din_en)
			din_r <= {0,din_r[7:1]};
		else 
			din_r <= din_r;
	end
	
	//在cnt=0时将计数结果赋给count_out
	//没有在cnt=8时赋值,是因为cnt0的逻辑比cnt1延迟了一个周期,因为前者受flag的影响
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			count_out <= 4'd0;
		else if(cnt == 4'd0)
			count_out <= cnt0;
		else 
			count_out <= count_out;
	end
	
endmodule

在这里插入图片描述

三、统计数据中1的个数

/*
	统计1的个数
*/
module cnt_num2(
	input clk,
	input rst_n,
	input din_en,
	input [7:0]din,
	output reg[3:0]count_out
);

	reg [3:0]cnt;//计数检测了多少bit
    reg [3:0]cnt1;//计数1的个数

	reg [7:0]din_r;//din的移位寄存器

	reg din_en_r;
	wire pos_din_en;
	
    localparam BitWidth = 8;
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			din_en_r <= 1'b0;
		else 
			din_en_r <= din_en;
	end

	assign pos_din_en = din_en && (!din_en_r);

	
	
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			cnt <= 4'd0;
		else if(din_en && (cnt < BitWidth))
			cnt <= cnt + 1'b1;
		else 
			cnt <= 4'd0;
	end

    //检测到1就加1,否则保持不变,检测完所有bit归零
    always@(posedge clk or negedge rst_n)begin
		if(!rst_n || pos_din_en)
			cnt1 <= 4'd0;
		else if(din_r[0] == 1)
			cnt1 <= cnt1 + 1'b1;
		else if (cnt < BitWidth) begin
            cnt1 <= cnt1;
        end
        else
			cnt1 <= 4'd0;
	end
	
    //din的右移移位寄存器,这样只需要每次检测最低位即可
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			din_r <= 8'd0;
		else if(pos_din_en)
			din_r <= din;
		else if(din_en)
			din_r <= {0,din_r[7:1]};
		else 
			din_r <= din_r;
	end
	
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			count_out <= 4'd0;
		else if(cnt == BitWidth)
			count_out <= cnt1;
		else 
			count_out <= count_out;
	end
	
endmodule

在这里插入图片描述

四、获取第一个1的位置


/*
	从低到高 记录第一个1的位置
*/
module cnt_num3(
	input clk,
	input rst_n,
	input din_en,
	input [7:0]din,
	output reg[2:0]index_out
);

	reg [3:0]cnt;//计数检测了多少bit
	reg flag;//检测到了第一个1
	reg [7:0]din_r;//din的移位寄存器

    reg [2:0]index;//记录第一个1的位置

	reg din_en_r;
	wire pos_din_en;
	localparam BitWidth = 8;

	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			din_en_r <= 1'b0;
		else 
			din_en_r <= din_en;
	end

	assign pos_din_en = din_en && (!din_en_r);

	
	
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			cnt <= 4'd0;
		else if(din_en && (cnt < BitWidth))
			cnt <= cnt + 1'b1;
		else 
			cnt <= 4'd0;
	end

	//判断是否已经检测到了第一个1
  	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
            index <= 3'd0;
            flag <= 1'b0;
        end
		else if((!flag) && din_r[0] && (cnt < BitWidth))begin
            flag <= 1'b1;
            index <= cnt;
        end
        else if (cnt == BitWidth) begin
            flag <= 1'b0;
            index <= 3'd0;
        end
        else begin
            flag <= flag;
            index <= index;
        end
            
			
	end

	//din的右移移位寄存器,这样只需要每次检测最低位即可
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			din_r <= 8'd0;
		else if(pos_din_en)
			din_r <= din;
		else if(din_en)
			din_r <= {0,din_r[7:1]};
		else 
			din_r <= din_r;
	end
	
	//在cnt=0时将计数结果赋给count_out
	//没有在cnt=8时赋值,是因为cnt0的逻辑比cnt1延迟了一个周期,因为前者受flag的影响
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			index_out <= 3'd0;
		else if(cnt == BitWidth)
			index_out <= index;
		else 
			index_out <= index_out;
	end
endmodule

在这里插入图片描述
需要注意的是代码中的一些逻辑,需要根据输入数据din和使能信号din_en的实际时序做出一些修改,但核心思想是差不多的!!!

posted @ 2021-12-13 21:32  耐心的小黑  阅读(1286)  评论(0编辑  收藏  举报