一、前言
當數據的位寬不是很長時,此類問題可以使用移位寄存器來解決。我們將輸入數據不斷的右移,這樣每次只需要對最后一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的實際時序做出一些修改,但核心思想是差不多的!!!