【问题标题】:How can I assign a "don't care" value to an output in a combinational module in Verilog如何在 Verilog 的组合模块中为输出分配“无关”值
【发布时间】:2015-06-09 15:56:40
【问题描述】:

假设我们要描述一个满足以下真值表的组合电路:

a b | s0 s1 s2 s3
-----------------
0 0 |  1  d  d  d
0 1 |  0  1  d  d
1 0 |  0  0  1  d
1 1 |  0  0  0  1

(其中d代表“don't care”值,即我们不关心这个输出的值是0还是1)

如果我们通过传统设计,我们可以利用这些“无关紧要”并为它们分配最方便的值,因此得到的方程(以及电路)是最简单的。例如,我们可以将之前的真值表改成这个:

a b | s0 s1 s2 s3
-----------------
0 0 |  1  1  1  1
0 1 |  0  1  0  1
1 0 |  0  0  1  1
1 1 |  0  0  0  1

最终的方程式将是(使用 Verilog 表示法):

s0 = ~a & ~b;
s1 = ~a;
s2 = ~b;
s3 = 1;

(请记住,您必须在 K-map 中为输出选择值,以便尽可能多地对单元格进行分组)

但是如果我选择使用 Verilog 来设计呢?我不能这样做:

module encoder (
  input wire a,
  input wire b,
  output reg [3:0] s
  );

  always @* begin
    case ({a,b})
      2'b00  : s = 4'b1ddd;
      2'b01  : s = 4'b01dd;
      2'b10  : s = 4'b001d;
      2'b11  : s = 4'b0001;
      default: s = 4'bdddd; 
    endcase
  end
endmodule

How to assign default values to outputs in a combinational always block... 告诉我,我也不能将 x 用作输出,只能用作输入。如果我使用z,则生成的电路在复杂性和使用的资源方面会更糟,因为需要三态缓冲器。

所以我不得不在设计时选择要输出的值(10),而这些值不必产生最优化的电路:

module encoder (
  input wire a,
  input wire b,
  output reg [3:0] s
  );

  always @* begin
    case ({a,b})
      2'b00  : s = 4'b1000;
      2'b01  : s = 4'b0100;
      2'b10  : s = 4'b0010;
      2'b11  : s = 4'b0001;
      default: s = 4'b0000; 
    endcase
  end
endmodule

这会导致这些等式(暂时忽略default 子句):

s0 = ~a & ~b;
s1 = ~a & b;
s2 = a & ~b;
s3 = a & b;

或者这个实现(取自 EdaPlayGround 的 YOSIS 0.3.0 的输出):

对于给定目标,这可能是也可能不是最佳解决方案,但这是我们允许合成器根据我们想要的输出来推断的。

使用针对 Spartan 3E-100k FPGA 的 XST 合成器,上述模块使用 2 个切片和 4 个 LUT

我假设 Verilog(或任何其他 HDL)应该让设计人员不必做这样的选择,因此如果设计人员允许它为给定的输出和为选择最方便的值,合成器可以应用任何可用的优化一组给定的输入。如果是这样的话,那么之前的设计可能会被优化为如下所示:

针对与上述相同的 FPGA,它使用 2 个切片和 3 个 LUT

对于这个例子,我已经能够手动进行优化,但考虑一个控制器模块,它有十几个输出到数据路径模块。对于控制器的给定状态,控制器的输出信号可能具有无关值。

例如:控制器从寄存器 A 或寄存器 B 向 select 输出一个信号,另一个信号使寄存器 C 的 load 使能,因此寄存器 C 可以加载 A 或 B,或保持其当前值.

如果load为0,我并不关心select的值,所以每次在控制器描述中我输出load = 0,我应该可以输出一个“不关心”到select.

所以我的问题是:

  • 有没有办法编写 Verilog(不是 SystemVerilog)描述,以便我可以为组合块的输出提供“无关值”?

  • 如果不是,这是语言的限制,还是“您应该进行设计,因此不需要‘无关’值”?


附录

令我惊讶的是,XST 将 `x` 识别为有效输出。它是可合成的并且似乎表现得像我预期的那样,导致使用 2 个切片和 3 个 LUT 实现相同的电路。另一方面,YOSIS 似乎忽略了它,并产生与非优化设计相同的输出。

修正:我用另一种设计测试了 XST:产生这个真值表的电路:

a b | s0 s1 s2 s3
-----------------
0 0 |  0  d  d  d
0 1 |  1  0  d  d
1 0 |  1  1  0  d
1 1 |  1  1  1  0

相应的 Verilog 模块,不用无关紧要编写,可以用多种方式编写,例如,这个:

module encoder (
  input wire a,
  input wire b,
  output reg [3:0] s
  );

  always @* begin
    case ({a,b})
      2'b00  : s = 4'b0111;
      2'b01  : s = 4'b1011;
      2'b10  : s = 4'b1101;
      2'b11  : s = 4'b1110;
      default: s = 4'b1111; 
    endcase
  end
endmodule

在最小化方面产生最差的结果(Spartan 3E FPGA 中的 2 个切片、4 个 LUT)

从这个真值表开始可以得到一个手工优化的版本:

a b | s0 s1 s2 s3
-----------------
0 0 |  0  0  0  0
0 1 |  1  0  1  0
1 0 |  1  1  0  0
1 1 |  1  1  1  0

这里很容易观察到,无需单个逻辑门即可获得 4 个输出中的 3 个。因此,XST 报告 1 个切片,1 个 LUT(计算 s0 所需的唯一一个)

module encoder (
  input wire a,
  input wire b,
  output reg [3:0] s
  );

  always @* begin
    case ({a,b})
      2'b00  : s = 4'b0000;
      2'b01  : s = 4'b1010;
      2'b10  : s = 4'b1100;
      2'b11  : s = 4'b1110;
      default: s = 4'b1110; // yes, same output as above
    endcase
  end
endmodule

如果使用 x 作为“无关紧要”的肮脏伎俩:

module encoder (
  input wire a,
  input wire b,
  output reg [3:0] s
  );

  always @* begin
    case ({a,b})
      2'b00  : s = 4'b0xxx;
      2'b01  : s = 4'b10xx;
      2'b10  : s = 4'b110x;
      2'b11  : s = 4'b1110;
      default: s = 4'bxxxx; 
    endcase
  end
endmodule

设计综合,但结果不是最小的。 XST 报告 1 个切片,2 个 LUT。

@Tim 在他的评论中链接的论文非常清楚地说明了这个问题:避免在你的设计中使用x。但是根据这个例子,语言不允许我们帮助合成器最小化电路。

节省一两个 LUT 可能不是什么大问题,但如果节省的成本允许此模块保留在一个切片内,则 P&R 将其放置在所需位置的工作将更少。

【问题讨论】:

  • 虽然您可以将 X 分配给输出,但我认为通常不鼓励这样做,因为它可能会导致潜在的危险综合后错误,而 RTL 模拟不会发现这些错误。值得一读:arm.com/files/pdf/Verilog_X_Bugs.pdf 通常,我认为通过显式分配 X 可以节省的少量门不值得在综合后设计中出现错误。
  • 好的。我承认分配 X 不是正式的方式(尽管它在 XST 中似乎表现得如预期),并且必须更多地被视为一个肮脏的把戏。我只是想指出它实际上是可合成的,因此,他们在链接问题中给我的答案并没有说出全部真相。
  • 顺便说一句:你链接的论文对我很有启发。总的结论是:“一般的指导原则是避免将无关 X 添加到 Verilog RTL 中,并使用良好的 RTL 编码实践来避免一些 X 问题(参见第 7.1 节)。”。我倾向于考虑“这种设计在合成时的行为方式”,而不是“这种设计在模拟时的行为方式”。考虑综合版本让我可以简化一些事情,比如会有零或一或高阻抗,但绝不会是 X 状态。
  • @mcleod_ideafix 你用什么程序来绘制这些数字(i.stack.imgur.com/X4eLh.png)?它们看起来非常赏心悦目。
  • 这是您执行合成时 YOSIS 的图形输出。您可以使用 edaplayground.com 上的在线 HDL 编辑器生成这些文件

标签: verilog


【解决方案1】:

当我使用 Quartus II 15.0 版时,将“don't care”分配给输出是可以的,并且生成了节省面积的电路。

例如,如果我合成这段代码,那:

module test1 (
input wire a,
input wire b,
output reg [3:0] s
);

always @* begin
  case ({a,b})
    2'b00  : s = 4'b1000;
    2'b01  : s = 4'b0100;
    2'b10  : s = 4'b0010;
    2'b11  : s = 4'b0001;
    default: s = 4'b0000; 
  endcase
end
endmodule

Quartus 生成了一个使用 5 个逻辑元件的电路。

但是,如果我在上面的代码中使用“无关”分配:

module test1 (
input wire a,
input wire b,
output reg [3:0] s
);

always @* begin
  case ({a,b})
    2'b00  : s = 4'b1xxx;
    2'b01  : s = 4'b01xx;
    2'b10  : s = 4'b001x;
    2'b11  : s = 4'b0001;
    default: s = 4'b0000; 
  endcase
end
endmodule

生成了仅使用 2 个逻辑元件 的电路。有趣的是,虽然总的逻辑元件使用较少,但生成的电路似乎更复杂。

我想知道生成的电路是否正确。所以我用使用“don't care”的电路运行了 Quartus 的模拟器。结果是我们想要的最简单的电路。

【讨论】:

    【解决方案2】:

    我认为将x 提供给输出就可以了——“未知”应该完全符合您的要求。我相信您可以直接将其连接为输出,但如果禁止这样做,您可以通过将 1 和 0 连接到输出来生成它。

    【讨论】:

    • 如果我尝试将01 连接到同一个输出,我会收到“多个驱动程序驱动相同的输出”错误,所以这是不可接受的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多