系统 Verilog 循环
System Verilog Loops
我目前正在研究 System Verilog 中的 Shift-Add 算法(32x32 位乘法)。 System Verilog 找不到任何错误,根据 GTKwave,我的代码工作正常。当我用 yosys 综合我的电路时,会添加锁存器。这就是问题所在。我不想在我的电路中使用闩锁。这是我的代码:
module multiplier(
input logic clk_i,
input logic rst_i,
input logic start_i,
input logic [31:0] a_i,
input logic [31:0] b_i,
output logic finished_o,
output logic [63:0] result_o
);
typedef enum logic [1:0] { STATE_A, STATE_B} state_t;
state_t state_p, state_n;
logic [63:0] fin_res;
logic [63:0] tmp;
logic rst_flag;
integer i;
always @(posedge clk_i or posedge rst_i) begin
if (rst_i == 1'b1) begin
state_p <= STATE_B;
end
else begin
state_p <= state_n;
end
end
always @(*)begin
state_n = state_p;
case (state_p)
STATE_A: if (start_i == 0) state_n = STATE_B;
STATE_B: if (start_i == 1) state_n = STATE_A;
default: state_n = state_p;
endcase
end
always @(*) begin
case (state_p)
STATE_A: begin
rst_flag = 1;
fin_res = 0;
finished_o = 0;
tmp = 0;
for (i = 0; i < 32; i = i + 1) begin
if (a_i[i] == 1'b1) begin
tmp = b_i;
tmp = tmp << i;
fin_res = fin_res + tmp;
end
end
end
STATE_B: begin
result_o = fin_res;
if (rst_flag == 1) finished_o = 1;
if (start_i == 1) finished_o = 0;
end
default: begin
finished_o = 0;
result_o = 0;
end
endcase
end
endmodule
在调试了 2 天之后,没有发现任何错误,我想问一下你是否可以帮助我。我正在分配每个输出(至少我是这么认为的)。那么我的错误在哪里?是for循环吗?但是这样做有什么问题呢?预先感谢您的帮助:)
代码片段的一些有用信息:start_i 是起始信号。如果将其设置为 1,则应开始乘法。 finished_o 是完成标志。如果将其设置为 1,CPU 将知道计算已完成。 a_i 和 b_i 是应该相乘的输入。 result_o是乘法的结果,当finished_o设置为1时可以读取。
根据 yosys,我得到以下锁存器:
64 DLATCH_N
64 DLATCH_P
我认为 for 循环中的 fin_res 可能有问题,因为逻辑变量和锁存器
一样长正好是 64 位
根据评论,您有一堆变量未在第二个 case 语句中分配,导致综合生成锁存器。为避免这种情况,您需要递归地分配 case 语句和条件语句的所有分支中的所有变量。
但是,如果有一个默认值可以分配给它们,您可以使用类似于第二个 always 块中的模式,只需在 'case' 语句之前分配默认值。这样你甚至不需要 default 子句,你也可以在第二个 always 块中去掉它。
always @(*) begin
// set default values
rst_flag = 0;
fin_res = 0;
finished_o = 0;
tmp = 0;
result_o = 0;
case (state_p)
STATE_A: begin
rst_flag = 1;
for (i = 0; i < 32; i = i + 1) begin
if (a_i[i] == 1'b1) begin
tmp = b_i;
tmp = tmp << i;
fin_res = fin_res + tmp;
end
end
end
STATE_B: begin
result_o = fin_res;
// are you sure that you do not need a latch here?
if (rst_flag == 1) finished_o = 1;
if (start_i == 1) finished_o = 0;
end
// you do not need 'default' here.
endcase
end
我的修复会导致组合行为,并且应该在综合中消除闩锁,但看起来它们的行为并不像您预期的那样。看起来你真的需要一个闩锁。
rst_flag 必须是闩锁。您在 STATE_A 中设置它并在 STATE_B 中使用它。它必须保持状态之间的价值。这是闩锁行为。
在 STATE_B 中,仅当满足某些条件时才更改 finished_o。如果 rst_flag 和 start_i 都为 0,会发生什么情况。您希望 finished_o 为 0还是以前的价值?在后一种情况下,您需要一个闩锁。
fin_res怎么样?你想在其他州用它做什么?保留先前的值(锁存器)或具有默认值(无锁存器)。
...
我目前正在研究 System Verilog 中的 Shift-Add 算法(32x32 位乘法)。 System Verilog 找不到任何错误,根据 GTKwave,我的代码工作正常。当我用 yosys 综合我的电路时,会添加锁存器。这就是问题所在。我不想在我的电路中使用闩锁。这是我的代码:
module multiplier(
input logic clk_i,
input logic rst_i,
input logic start_i,
input logic [31:0] a_i,
input logic [31:0] b_i,
output logic finished_o,
output logic [63:0] result_o
);
typedef enum logic [1:0] { STATE_A, STATE_B} state_t;
state_t state_p, state_n;
logic [63:0] fin_res;
logic [63:0] tmp;
logic rst_flag;
integer i;
always @(posedge clk_i or posedge rst_i) begin
if (rst_i == 1'b1) begin
state_p <= STATE_B;
end
else begin
state_p <= state_n;
end
end
always @(*)begin
state_n = state_p;
case (state_p)
STATE_A: if (start_i == 0) state_n = STATE_B;
STATE_B: if (start_i == 1) state_n = STATE_A;
default: state_n = state_p;
endcase
end
always @(*) begin
case (state_p)
STATE_A: begin
rst_flag = 1;
fin_res = 0;
finished_o = 0;
tmp = 0;
for (i = 0; i < 32; i = i + 1) begin
if (a_i[i] == 1'b1) begin
tmp = b_i;
tmp = tmp << i;
fin_res = fin_res + tmp;
end
end
end
STATE_B: begin
result_o = fin_res;
if (rst_flag == 1) finished_o = 1;
if (start_i == 1) finished_o = 0;
end
default: begin
finished_o = 0;
result_o = 0;
end
endcase
end
endmodule
在调试了 2 天之后,没有发现任何错误,我想问一下你是否可以帮助我。我正在分配每个输出(至少我是这么认为的)。那么我的错误在哪里?是for循环吗?但是这样做有什么问题呢?预先感谢您的帮助:)
代码片段的一些有用信息:start_i 是起始信号。如果将其设置为 1,则应开始乘法。 finished_o 是完成标志。如果将其设置为 1,CPU 将知道计算已完成。 a_i 和 b_i 是应该相乘的输入。 result_o是乘法的结果,当finished_o设置为1时可以读取。
根据 yosys,我得到以下锁存器:
64 DLATCH_N
64 DLATCH_P
我认为 for 循环中的 fin_res 可能有问题,因为逻辑变量和锁存器
一样长正好是 64 位根据评论,您有一堆变量未在第二个 case 语句中分配,导致综合生成锁存器。为避免这种情况,您需要递归地分配 case 语句和条件语句的所有分支中的所有变量。
但是,如果有一个默认值可以分配给它们,您可以使用类似于第二个 always 块中的模式,只需在 'case' 语句之前分配默认值。这样你甚至不需要 default 子句,你也可以在第二个 always 块中去掉它。
always @(*) begin
// set default values
rst_flag = 0;
fin_res = 0;
finished_o = 0;
tmp = 0;
result_o = 0;
case (state_p)
STATE_A: begin
rst_flag = 1;
for (i = 0; i < 32; i = i + 1) begin
if (a_i[i] == 1'b1) begin
tmp = b_i;
tmp = tmp << i;
fin_res = fin_res + tmp;
end
end
end
STATE_B: begin
result_o = fin_res;
// are you sure that you do not need a latch here?
if (rst_flag == 1) finished_o = 1;
if (start_i == 1) finished_o = 0;
end
// you do not need 'default' here.
endcase
end
我的修复会导致组合行为,并且应该在综合中消除闩锁,但看起来它们的行为并不像您预期的那样。看起来你真的需要一个闩锁。
rst_flag 必须是闩锁。您在 STATE_A 中设置它并在 STATE_B 中使用它。它必须保持状态之间的价值。这是闩锁行为。
在 STATE_B 中,仅当满足某些条件时才更改 finished_o。如果 rst_flag 和 start_i 都为 0,会发生什么情况。您希望 finished_o 为 0还是以前的价值?在后一种情况下,您需要一个闩锁。
fin_res怎么样?你想在其他州用它做什么?保留先前的值(锁存器)或具有默认值(无锁存器)。
...