如何在Verilog的组合模块中为输出分配"不关心"值

mcl*_*fix 14 verilog

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

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
Run Code Online (Sandbox Code Playgroud)

(其中,d代表"不关心"值,也就是说,我们不关心此输出的值是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
Run Code Online (Sandbox Code Playgroud)

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

s0 = ~a & ~b;
s1 = ~a;
s2 = ~b;
s3 = 1;
Run Code Online (Sandbox Code Playgroud)

(记住你必须在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
Run Code Online (Sandbox Code Playgroud)

有人告诉我如何将默认值分配给组合中的输出始终阻止...我也不能将其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
Run Code Online (Sandbox Code Playgroud)

这导致这些方程式(default暂时忽略该条款):

s0 = ~a & ~b;
s1 = ~a & b;
s2 = a & ~b;
s3 = a & b;
Run Code Online (Sandbox Code Playgroud)

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

实现非优化器编码器

哪个可能是也可能不是给定目标的最佳解决方案,但它是我们允许合成器根据我们想要的输出推断的.

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

我假设Verilog(或任何其他HDL)应该让设计者不必做出这样的选择,因此如果设计师允许它为给定输出和给定集合选择最方便的值,则合成器可以应用任何可用的优化.投入 如果是这种情况,那么之前的设计可能已经优化为如下所示:

编码器优化

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

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

例如:控制器select从寄存器A或寄存器B 输出信号,另一个信号用于load寄存器C的使能,因此寄存器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
Run Code Online (Sandbox Code Playgroud)

相应的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
Run Code Online (Sandbox Code Playgroud)

就最小化而言,这会产生最差的结果(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
Run Code Online (Sandbox Code Playgroud)

这里很容易观察到,在没有单个逻辑门的情况下,可以获得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
Run Code Online (Sandbox Code Playgroud)

如果使用肮脏的技巧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
Run Code Online (Sandbox Code Playgroud)

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

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

保存一个或两个LUT可能不是很多,但如果节省的费用允许这个模块保持在一个切片内,P&R将把它放在任何需要的地方的工作量会减少.

Tag*_*san 6

当我使用 Quartus II ver 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
Run Code Online (Sandbox Code Playgroud)

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

但是,如果我在上面的代码中使用“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'b1xxx;
    2'b01  : s = 4'b01xx;
    2'b10  : s = 4'b001x;
    2'b11  : s = 4'b0001;
    default: s = 4'b0000; 
  endcase
end
endmodule
Run Code Online (Sandbox Code Playgroud)

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

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


Gre*_*ton -3

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