Verilog - 在单个 always 块中两次为 reg 赋值
Verilog - Assigning value to a reg twice in a single always block
我正在开发一个计数器,用于计算可变宽度的输入比特流中高位的位数。代码如下:
module counter(i_clk, i_arst, i_data, o_done, o_cnt);
// ---------------------------------------- SIGNALS ---------------------------------------- //
// Parameters
parameter OUT_WIDTH; // Width of the output in bits
parameter IN_WIDTH; // Number of bits in an input bit stream
// Input
input wire i_clk; // Clock
input wire i_arst; // Active high asynchronous reset
input wire i_data; // Input data
// Outputs
output reg o_done; // Output done bit
output reg[OUT_WIDTH-1:0] o_cnt; // WIDTH-bit output counter
// Internal signals
integer index; // Bit index for the input
reg[OUT_WIDTH-1:0] r_cnt_tmp; // Temporary counter for assignment
// ---------------------------------------- LOGIC ---------------------------------------- //
// Combinational logic
always @(*) begin
o_cnt = r_cnt_tmp;
end
// Sequential logic
always @(posedge i_clk or posedge i_arst) begin
// Reset the counter
if(i_arst) begin
r_cnt_tmp <= {OUT_WIDTH{1'b0}};
o_done <= 1'b0;
index <= 0;
end
else begin
// When a new bit stream arrives
if(index == 0) begin
r_cnt_tmp <= {OUT_WIDTH{1'b0}}; // Reset the output data
o_done <= 1'b0; // Data is now invalid because it is a new bit stream
// It only happens after a reset or a valid data output
end
// If bit is set
if(i_data == 1'b1) begin
r_cnt_tmp <= r_cnt_tmp + 1; // Count up
end
index <= index + 1; // Increment the index
if(index == IN_WIDTH) begin // The input has been completely looped over
o_done <= 1'b1; // Data is now valid for the output
index <= 0; // Reset the index
end
end
end
endmodule
完成当前比特流后,我设置 o_done 信号以通知输出数据有效,并且我重置变量索引以从新的比特流开始。然后在下一个时钟上升沿,我重置 o_done 信号和计数器值并重新开始计数。
我的问题是我的计数器并不总是重置。由于信号仅在块末尾取值,如果比特流的第一位为高,则不会重置。
我想在同一个时钟周期内重置并再次开始计数,因为我不想要更多的延迟,而且我有连续的比特流到达输入端。
有没有办法避免这个问题?
感谢您的帮助。
我认为您的问题出在这些陈述中:
// When a new bit stream arrives
if(index == 0) begin
r_cnt_tmp <= {OUT_WIDTH{1'b0}}; // Reset the output data
o_done <= 1'b0; // Data is now invalid because it is a new bit stream
// It only happens after a reset or a valid data output
end
// If bit is set
if(i_data == 1'b1) begin
r_cnt_tmp <= r_cnt_tmp + 1; // Count up
end
假设您有 index == 0
和 i_data == 1
。现在,r_cnt_tmp 值将在块执行后被安排为 0
,因为您在那里使用了非阻塞赋值。
下一个块将尝试增加该值,但它将使用计数器的 旧 值,并且会愉快地覆盖先前计划的重置值。它很可能不会是“1”或“0”。
重写它的一种方法如下。在该示例中,如果 i_data 为“1”而索引为 0,则计数器的初始值将变为“1”。
// When a new bit stream arrives
if(index == 0) begin
r_cnt_tmp <= i_data; // Reset the output data to '0' or '1' depending on i_data
o_done <= 1'b0; // Data is now invalid because it is a new bit stream
// It only happens after a reset or a valid data output
end
else if(i_data == 1'b1) begin // you definitely need this 'else'
r_cnt_tmp <= r_cnt_tmp + 1; // Count up
end
抱歉,我还没有测试过,尤其是当 i_data 为 'x' 时。
您可能需要不同的初始条件要求。所以,你可以按照自己的方式来写。
我正在开发一个计数器,用于计算可变宽度的输入比特流中高位的位数。代码如下:
module counter(i_clk, i_arst, i_data, o_done, o_cnt);
// ---------------------------------------- SIGNALS ---------------------------------------- //
// Parameters
parameter OUT_WIDTH; // Width of the output in bits
parameter IN_WIDTH; // Number of bits in an input bit stream
// Input
input wire i_clk; // Clock
input wire i_arst; // Active high asynchronous reset
input wire i_data; // Input data
// Outputs
output reg o_done; // Output done bit
output reg[OUT_WIDTH-1:0] o_cnt; // WIDTH-bit output counter
// Internal signals
integer index; // Bit index for the input
reg[OUT_WIDTH-1:0] r_cnt_tmp; // Temporary counter for assignment
// ---------------------------------------- LOGIC ---------------------------------------- //
// Combinational logic
always @(*) begin
o_cnt = r_cnt_tmp;
end
// Sequential logic
always @(posedge i_clk or posedge i_arst) begin
// Reset the counter
if(i_arst) begin
r_cnt_tmp <= {OUT_WIDTH{1'b0}};
o_done <= 1'b0;
index <= 0;
end
else begin
// When a new bit stream arrives
if(index == 0) begin
r_cnt_tmp <= {OUT_WIDTH{1'b0}}; // Reset the output data
o_done <= 1'b0; // Data is now invalid because it is a new bit stream
// It only happens after a reset or a valid data output
end
// If bit is set
if(i_data == 1'b1) begin
r_cnt_tmp <= r_cnt_tmp + 1; // Count up
end
index <= index + 1; // Increment the index
if(index == IN_WIDTH) begin // The input has been completely looped over
o_done <= 1'b1; // Data is now valid for the output
index <= 0; // Reset the index
end
end
end
endmodule
完成当前比特流后,我设置 o_done 信号以通知输出数据有效,并且我重置变量索引以从新的比特流开始。然后在下一个时钟上升沿,我重置 o_done 信号和计数器值并重新开始计数。
我的问题是我的计数器并不总是重置。由于信号仅在块末尾取值,如果比特流的第一位为高,则不会重置。
我想在同一个时钟周期内重置并再次开始计数,因为我不想要更多的延迟,而且我有连续的比特流到达输入端。
有没有办法避免这个问题?
感谢您的帮助。
我认为您的问题出在这些陈述中:
// When a new bit stream arrives
if(index == 0) begin
r_cnt_tmp <= {OUT_WIDTH{1'b0}}; // Reset the output data
o_done <= 1'b0; // Data is now invalid because it is a new bit stream
// It only happens after a reset or a valid data output
end
// If bit is set
if(i_data == 1'b1) begin
r_cnt_tmp <= r_cnt_tmp + 1; // Count up
end
假设您有 index == 0
和 i_data == 1
。现在,r_cnt_tmp 值将在块执行后被安排为 0
,因为您在那里使用了非阻塞赋值。
下一个块将尝试增加该值,但它将使用计数器的 旧 值,并且会愉快地覆盖先前计划的重置值。它很可能不会是“1”或“0”。
重写它的一种方法如下。在该示例中,如果 i_data 为“1”而索引为 0,则计数器的初始值将变为“1”。
// When a new bit stream arrives
if(index == 0) begin
r_cnt_tmp <= i_data; // Reset the output data to '0' or '1' depending on i_data
o_done <= 1'b0; // Data is now invalid because it is a new bit stream
// It only happens after a reset or a valid data output
end
else if(i_data == 1'b1) begin // you definitely need this 'else'
r_cnt_tmp <= r_cnt_tmp + 1; // Count up
end
抱歉,我还没有测试过,尤其是当 i_data 为 'x' 时。
您可能需要不同的初始条件要求。所以,你可以按照自己的方式来写。