【问题标题】:System Verilog Loops系统 Verilog 循环
【发布时间】:2020-11-12 19:22:59
【问题描述】:

我目前正在研究 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 语句编写了一个闩锁。例如,您不会在每种情况下都分配 finished_o(您使用 'if' 而没有其他情况)。
  • 还有rst_flag,因为如果state_p 不是STATE_A,则不会分配它
  • 是的,但即使修复了这些,也不会改变任何关于闩锁的事情。
  • 好的,我修好了。有时重写整个代码比寻找错误更好......谢谢帮助:)
  • 还有fin_res,可能还有tmp

标签: verilog system-verilog cpu-architecture hdl yosys


【解决方案1】:

从评论中,您有一堆未在第二个 case 语句中分配的变量,导致综合生成锁存器。为避免这种情况,您需要递归地分配 case 语句和条件语句的所有分支中的所有 var。

但是,如果您可以为所有这些分配一个默认值,您可以使用类似于第二个 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

我的修复将导致组合行为,并且应该在综合中摆脱锁存器,但看起来它们的行为不像您预期​​的那样。看来您真的需要一个闩锁

  1. rst_flag 必须是一个锁存器。您在 STATE_A 中设置它并在 STATE_B 中使用它。它必须保持状态之间的值。这是一种闩锁行为。

  2. 在 STATE_B 中,只有在满足某些条件时才更改 finished_o。如果 rst_flagstart_i 都为 0,会发生什么情况。您希望 finished_o 为 0 还是之前的值?在后一种情况下,您需要一个闩锁。

  3. fin_res 怎么样?你想在其他州用它做什么?保留以前的值(锁存器)或具有默认值(无锁存器)。

...

【讨论】:

  • 是的,你是对的。我的代码中需要闩锁。我重写了整个代码,所以我现在没有任何锁存器。感谢您的帮助:)
猜你喜欢
  • 1970-01-01
  • 2014-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多