次の真理値表を満たす組み合わせ回路について説明したいとします。
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
私は 組み合わせブロックの出力にデフォルト値を割り当てる方法... で、出力として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の出力から取得):
これは、特定のターゲットに最適なソリューションである場合とそうでない場合がありますが、これは、シンセサイザが出力wantを考慮して推論できるようにするものです。
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
を使用しないでください。しかし、この例によれば、この言語ではシンセサイザが回路を最小化するのを助けることができません。
1つまたは2つのLUTを保存することは大したことではないかもしれませんが、この保存によりこのモジュールがスライス内に留まることができる場合、P&Rは必要な場所に配置するための作業が少なくなります。
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論理エレメントを使用する回路を生成しました。
ただし、上記のコードで「ドントケア」割り当てを使用する場合:
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のシミュレータを実行しました。結果は、私たちが望む最も単純な回路です。