首页 > 解决方案 > 将 x(无关)分配给寄存器复位值或组合输出以提高区域效率

问题描述

我的问题是关于 FPGA 设计的——如果我的设计中有一些寄存器我不在乎它们的复位值是多少,我可以将复位值设置为 x 吗?这会提高面积效率(合成器是否能够利用这一点并以更有效的方式生成设计?)例如,

always @(posedge clk or negedge reset_n) begin
    if(~reset_n) begin
        reg_1 <= 'x
    end
...
end

编辑:另一个类似主题的问题——假设我有一个状态机,例如我不在乎某些状态下的某些输出是什么——将它们设置为 'x 会提高区域效率吗?例如,如果我有一个具有两个状态的 fsm,STATE_1、STATE_2 和两个输出,那么综合工具将能够使用以下代码:

always_comb begin
   case(state):
   STATE_1:begin
      out_1 = 1;
      out_2 = x;
   end
   STATE_2:begin
      out_1 = x;
      out_2 = 0;
   end
end

比这更好:

always_comb begin
   case(state):
   STATE_1:begin
      out_1 = 1;
      out_2 = 0;
   end
   STATE_2:begin
      out_1 = 0;
      out_2 = 0;
   end
end

(假设我不在乎 STATE_1 中的 out_2 是什么,以及 STATE_2 中的 out_1 是什么)。谢谢

标签: verilogsystem-verilogfpga

解决方案


'x在顺序逻辑中使用

是的,在 Verilog 方面,您可以使用这种语法。但是,在您的特定示例中,这样做并没有真正意义,您可能会认为这是一种糟糕的编码实践。除了显式分配'x,您还可以省略异步重置。

以下两个过程将综合到同一个触发器。我个人建议使用后一种风格。

// Assigning 'x to tell synthesis tool that there is no reset value
always @(posedge clk or negedge reset_n)
   if(~reset_n)
      reg_1 <= 'x;
   else
      reg_1 <= reg_1_next;


// Omitting the asynchronous reset from the sensitivity list to tell
// synthesis tool that there is no reset
always @(posedge clk)
   reg_1 <= reg_1_next;
    

一般来说:如果您有不同的变量必须是可重置或不可重置的,您应该将它们的分配拆分为不同的always块。这通常会使您的代码更具可读性。请参见下面的示例:

// Do NOT do this
always @(posedge clk or negedge reset_n)
   if(~reset_n) 
   begin
      vld   <= 1'b0;
      reg_1 <= 'x;
   end
   else
   begin
      vld   <= vld_next;
      reg_1 <= reg_1_next;
   end


// Do this
always @(posedge clk or negedge reset_n)
   if(~reset_n) 
      vld   <= 1'b0;
   else
      vld   <= vld_next;

always @(posedge clk)
    reg_1 <= reg_1_next;

奖金

'x话虽如此,在某些情况下,分配复位条件以告诉综合工具不要为特定变量生成可复位触发器是有意义的。请看一下这个答案:https ://stackoverflow.com/a/21477457/7949​​378

让我们根据这个答案创建一个示例。假设您有一个具有 1 个有效信号 ( vld) 和 2 个数据信号 ( data_aand data_b) 的结构。数据仅在 为 时vld有效1'b1。换句话说,我们可以通过只重置vld而不重置data_aand来节省面积data_b

现在,我们想利用结构的全部潜力,并简单地分配完整的结构而不是单独的成员(请参阅 参考资料struct_example_q <= struct_example_next;)。这意味着我们不能将此always-block 拆分为两个单独的进程(就像我之前推荐的那样)。在这种情况下,我们必须明确告诉综合工具不要重置数据信号。

请看下面的代码:

   typedef struct {
      logic        vld;
      logic [31:0] data_a;
      logic [31:0] data_b;
  } struct_example_t;

  struct_example_t struct_example_next;
  struct_example_t struct_example_q;

  always @(posedge clk or negedge reset_n)
     if (!reset_n)
     begin
         /**
          * Only reset the valid-bit
          * We could use '{default:'x} to simplify this even further
          **/
         struct_example_q.data_a <= 'x;
         struct_example_q.data_b <= 'x;
         struct_example_q.vld    <= 1'b0;
     end
     else
     begin
         struct_example_q <= struct_example_next;
     end

'x在组合逻辑中使用

让我们先看看你的 RTL:

always_comb begin
   case(state):
   STATE_1:begin
      out_1 = 1;
      out_2 = x;
   end
   STATE_2:begin
      out_1 = x;
      out_2 = 0;
   end
end

我想指出,这并不是最好的例子。假设 FSM 是满的——也就是说,这STATE_1STATE_2唯一state可以采取的两种状态——你会用下面的代码实现完全相同的效果,假设你无论如何都不用 caseout_1out_2在其他状态下。

always_comb begin
    out_1 = 1;
    out_2 = 0;
end

现在,为了这个例子,让我们假设我们不能重写它。在这种情况下,您应该在案例陈述之前设置默认值。这可以防止综合逻辑在您的无关状态下推断锁存器,但它也可以帮助您在开始进行门级仿真 (GLS)时不会遇到问题。'x使用您的示例,您的 RTL 将如下面的代码所示。(再次注意,这里的情况有点多余。)

always_comb begin
   out_1 = 1;
   out_2 = 0;

   case(state):
   STATE_1:begin
      out_1 = 1;
   end
   STATE_2:begin
      out_2 = 0;
   end
end

一旦你有了更精细的 FSM,你就会发现这个策略是有意义的。


奖金

我想举一个使用uniqueorpriority有意义的例子(而不是'x作为默认值使用)。看看下面的 RTL 并假设它select == 3'b0永远不会发生:

always_comb
begin
    out_1 = 'x;

    case (1'b1)
        select[0]: out_1 = a & b;
        select[1]: out_1 = a ^ b;
        select[2]: out_1 = a | b;
    endcase
end

设置默认值out_1将阻止逻辑推断锁存器(因为它不知道select == 3'b0永远不会发生)。此外,'x此处将帮助综合工具优化此逻辑(不一定是 wrt 区域!)。然而,正如我们之前所讨论的,使用'x通常被认为是不好的做法。

您可以不使用默认值,而是使用priority关键字告诉综合工具已列出所有有效案例,并且该工具必须按顺序评估您的案例。因此,以下情况也将被视为已满:

always_comb
    priority case (1'b1)
        select[0]: out_1 = a & b;
        select[1]: out_1 = a ^ b;
        select[2]: out_1 = a | b;
    endcase

此外,如果您可以确定这select是一个单热信号 ( $countones(select) == 1),则可以使用unique关键字。这将告诉综合工具这是完全并行的情况

always_comb
    unique case (1'b1)
        select[0]: out_1 = a & b;
        select[1]: out_1 = a ^ b;
        select[2]: out_1 = a | b;
    endcase

请注意,如果您违反了使用priorityunique.


推荐阅读