想象一下,我们想描述一个满足以下真值表的组合电路:
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
,由于需要三态缓冲区,所得到的电路在复杂性和使用的资源方面更差。
所以我不得不在设计时选择我想要输出的值(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
,我应该能够输出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将把它放在任何需要的地方的工作量会减少。
答案 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
然而,如果我使用"不关心"上面代码中的赋值:
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个逻辑元素的电路。有趣的是,尽管总逻辑元件使用较少,但生成的电路似乎更复杂。
我想知道生成的电路是否正确。所以我运行了Quartus的模拟器,其中使用的是“不在乎”的电路"。结果是我们想要的最简单的电路。
答案 1 :(得分:-2)
我认为向输出提供x
可以解决问题 - "未知"应该做你想要的。我相信你可以直接将它作为输出连接,但是如果这是禁止的,你可以通过将1和0连接到输出来生成它。