想象一下,我们想要描述一个满足以下真值表的组合电路:
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
,所产生的电路在复杂性和使用的资源方面甚至更差,因为需要三态缓冲器.
所以我不得不在设计时选择我想要输出的值(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
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将把它放在任何需要的地方的工作量会减少.
当我使用 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)
但是,如果我在上面的代码中使用“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 的模拟器。结果是我们想要的最简单的电路。