【发布时间】: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,则生成的电路在复杂性和使用的资源方面会更糟,因为需要三态缓冲器。
所以我不得不在设计时选择要输出的值(1 或 0),而这些值不必产生最优化的电路:
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