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

时间:2015-04-04 20:38:36

标签: 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

(其中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

最终的方程是(使用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的输出):

Implementation of non optimizer encoder

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

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

我认为Verilog(或任何其他HDL)应该让设计者不必做出这样的选择,因此如果设计师允许它为给定输出选择最方便的值,那么合成器可以应用任何可用的优化。一组给定的输入。如果是这种情况,那么之前的设计可能已经过优化,看起来像这样:

Encoder optimized

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

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

例如:控制器从寄存器A或寄存器B向select输出信号,而另一个信号用于启用寄存器C的load,因此寄存器C可以加载A或B,或者保持现有价值。

Datapath

如果load为0,我真的不关心select的值,所以每次在控制器描述中我输出load = 0,我应该能够输出a"不要照顾"到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

在最小化方面产生最差结果(2片,Spartan 3E FPGA中有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将把它放在任何需要的地方的工作量会减少。

2 个答案:

答案 0 :(得分:3)

当我使用Quartus II ver 15.0时,请不要关心"不要关心"输出正常,生成区域效率电路。

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

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个逻辑元素的电路。 not optimized

然而,如果我使用"不关心"上面代码中的赋值:

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个逻辑元素的电路。有趣的是,尽管总逻辑元件使用较少,但生成的电路似乎更复杂。 optimized

我想知道生成的电路是否正确。所以我运行了Quartus的模拟器,其中使用的是“不在乎”的电路"。结果是我们想要的最简单的电路。 enter image description here

答案 1 :(得分:-2)

我认为向输出提供x可以解决问题 - "未知"应该做你想要的。我相信你可以直接将它作为输出连接,但是如果这是禁止的,你可以通过将1和0连接到输出来生成它。