HDLコードを実装する際に守るべきベストプラクティスは何ですか?
より一般的なソフトウェア開発分野と比較した場合の共通点と相違点は何ですか?
このトピックに関する最良の本は Reuse Methodology Manual です。 VHDLとVerilogの両方をカバーしています。
そして特に、ソフトウェアで完全に一致しないいくつかの問題:
同じものが含まれます
古いスレッドのようですが、私の$ 0.02を入れたかったのです。これは実際にはVerilog/VHDLに固有のものではありません。ハードウェア設計全般についての詳細...特にカスタムASICの合成可能な設計。
これは私の設計です意見(学術ではなく)業界における長年の設計経験に基づいています。順不同
私の包括的ステートメントは、検証を実行するための設計です。ハードウェア設計では、検証が最も重要です。実際のシリコンで見つかったバグは、はるかに高価です。単に再コンパイルすることはできません。したがって、プレシリコンははるかに焦点を当てています。
制御パスとデータパスの違いを理解します。これにより、はるかにエレガントで保守可能なコードを作成できます。また、ゲートを保存してX伝播を最小限に抑えることができます。たとえば、データパスにはリセット可能なフロップは必要ありませんが、制御パスには常に必要です。
検証前に機能を証明します。形式的なアプローチまたは波形を通して。これには多くの利点があります。2つ説明します。1つ目は、問題によるタマネギの皮むきの無駄な時間を節約できます。多くのアプリケーションレベルの設計(学習中のesp)およびほとんどのコース作業とは異なり、コード変更のターンアラウンドタイムは非常に長くなります(複雑さに応じて10分から数日まで)。コードを変更するたびに、エラボレーション、糸くずのチェック、コンパイル、波形の立ち上げ、最後に実際のシミュレーションを実行する必要があります。第二に、コーナーケースをヒットするのが難しい可能性がはるかに低くなります。これはシリコン前の検証に関するものであることに注意してください。これらはきっとあなたにたくさんの$$$を費やすポストシリコンでヒットするでしょう。私を信じてください。機能を証明するための先行費用はリスクを大幅に最小化し、努力する価値があります。これは、最近の大学の卒業生を説得するのが難しい場合があります。
「チキンビット」を持っている。チキンビットは、シリコンの機能を無効にするためにドライバーを介して設定されたMMIOのビットです。これは、信頼性が高くない変更を元に戻すことを目的としています(信頼性は検証作業に正比例します)。プレシリコンのすべての可能な状態にぶつかることはほとんど不可能です。ポストシリコンで証明されるまで、デザインに対する信頼は本当に満たすことができません。バグを公開する時間の0.000005%ヒットした状態が1つしかない場合でも、ポストシリコンではヒットしますが、必ずしもプレシリコンではヒットしません。
すべてのコストで制御パスの例外を回避します。新しい例外が発生するたびに、検証作業が2倍になります。これは説明するのが難しいです。別のブロックが使用するメモリにデータを保存するDMA=ブロックがあるとしましょう。保存されたデータ構造は、実行されているいくつかの機能に依存しているとしましょう。保存されたデータ構造が関数ごとに異なることを確認するには、検証作業にDMA関数の数を掛けただけです。このルールに従えば、保存されたデータ構造はスーパーセットになります。 DMA保存ロジックが1つの関数に対して検証されると、すべての関数に対して検証されます。
インターフェイスを最小化します(最小化制御パスを読み取ります)。これは、例外の最小化に関連しています。まず、すべての新しいインターフェースには検証が必要です。これには、テストベンチの新しいチェッカー/トラッカー、アサーション、カバレッジポイント、バス機能モデルが含まれます。第二に、それはあなたの検証努力を飛躍的に増やすことができます!キャッシュ内のデータを読み取るためのインターフェースが1つあるとします。ここで(奇妙な理由で)メインメモリを読み取るための別のインターフェイスが必要だと判断したとしましょう。検証作業を4倍にしました。次に、これらの組み合わせをいつでも検証する必要がありますn:
前提を理解して伝達します。これがないことは、通信の問題をブロックするためのブロックの主な理由です。完全に検証された完全なブロックを作成できます。ただし、すべての前提を理解しないと、ブロックは接続時に失敗します。
潜在的な状態を最小限に抑えます。設計の状態(意図的または非意図的)が少ないほど、検証に必要な労力は少なくなります。同様の関数を1つの最上位関数(シーケンサーやアービターなど)にグループ化することをお勧めします。この高レベルの関数を識別して定義し、可能な限り多くの小さな関数を包含するようにすることは非常に困難ですが、そうすることで状態を大幅に排除し、バグの可能性を排除できます。
常にあなたのブロックを離れる強い信号を提供してください。ほとんどの場合、それはフロップです。エンドポイントブロックがそれをどのように処理するかがわかりません。完全な実装に直接影響を与える可能性のあるタイミングの問題に遭遇する可能性があります。
パフォーマンスに悪影響が及ばない限り、食事の多いタイプのFSMは避けてください。 Mealy FSMはMooreよりもタイミングの問題を引き起こす可能性が高い
..そして最後に、私が最も嫌いなもの:「壊れていない場合は修正しないでください」リスクを伴うこととバグのコストが高いため、ハッキングは問題を解決するためのより現実的な解決策です。他には、既存のコンポーネントの利用に言及することによってこれを回避しました。
さらに比較することについて伝統的ソフトウェア設計:
離散イベント駆動型プログラミングは、まったく異なるパラダイムです。人々はverilog構文を見て、「ああ、それはCのようだ」と思います...しかし、これは真実から離れることはできません。構文は似ていますが、考え方は異なります。たとえば、従来のデバッガーは、合成可能なRTLでは実質的に無意味です(テストベンチの設計は異なります)。紙の上の波形は、利用可能な最良のツールです。ただし、そうは言っても、FSM設計は、手続き型プログラミングを模倣する場合があります。ソフトウェアのバックグラウンドを持つ人々は、FSMに夢中になる傾向があります(私は最初はそうでした)。
System Verilogには、数多くのテストベンチ固有の機能があります。それは完全にオブジェクト指向です。テストベンチの設計に関しては、従来のソフトウェア設計と非常によく似ています。ただし、それに関連付けられているディメンションが1つあります。それは時間のディメンションです。競合状態とプロトコル遅延を考慮する必要があります
検証に関しては、それも異なります(そして同じです)。主なアプローチは3つあります。
...完全を期すために、テストベンチ設計のベストプラクティスについても説明する必要があります...しかし、それは別の日です
長さでごめんなさい..私は「ゾーン」にいた:)
VerilogやVHDLのようなHDLは、本当にスパゲッティコードを奨励しているようです。ほとんどのモジュールは、いくつかの「always」(Verilog)または「process」(VHDL)ブロックで構成され、任意の順序にすることができます。モジュールの全体的なアルゴリズムまたは機能は、しばしば完全に隠されています。コードがどのように機能するかを理解する(作成しなかった場合)のは、骨の折れるプロセスです。
数年前、私はVHDL設計のためのより構造化された方法を概説する この論文 に出くわしました。基本的な考え方は、各モジュールには2つのプロセスブロックしかないということです。 1つは組み合わせコード用、もう1つは同期コード(レジスタ)用です。可読性と保守性の高いコードを作成するのに最適です。
hDLでは、コードの一部が同時に動作する場合があります。たとえば、2行のコードが同時に「動作する」場合があります。これは、賢く使用する利点です。これは、行ごとの言語に慣れているプログラマが最初は理解しにくいかもしれません。
起動プロセスには特別な注意を払う必要があります-チップが機能するようになったら、あなたは大きな方法を作りました。
ハードウェアでのデバッグは、通常、ソフトウェアのデバッグよりもはるかに困難です。
単純なコードが推奨されます。たとえば、より高速のチップを使用するなど、コードが既に実行された後、コードを高速化する他の方法がある場合があります。
コンポーネント間の「スマート」プロトコルを避けます。
ハードウェアはデバッグが難しいので再利用し、一部は無料で一部は無料で販売されているモジュールの「ライブラリ」の使用を検討するため、HDLの作業コードは他のソフトウェアよりも貴重です。
設計では、HDLコードのバグだけでなく、プログラミングしているチップ、およびチップとインターフェイスする他のハードウェアデバイスの障害も考慮する必要があるため、チェックしやすい設計について本当に考える必要があります。
デバッグのヒント:
デザインに複数のビルディングブロックが含まれている場合、それらのブロック間のインターフェイスからチップの外側のテストポイントまでラインを作成することをお勧めします。
外部デバイスで検査する興味深いデータをそらすために、デザインに十分なラインを保存する必要があります。また、この行を使用して、コードを実行の現在の状態を通知する方法として使用できます。たとえば、ある時点でデータを受け取った場合、行に値を書き込み、実行の後半で別の値を書き込みます。 、など」
チップが再構成可能であれば、特定のテストを調整し、各テストの出力を再プログラムできるので、これはさらに便利になります(これはledsで非常によく見えます)。 )
編集:
スマートプロトコルとは、2つの物理ユニットが接続された場合、利用可能な最も単純な通信プロトコルと通信することを意味します。つまり、それらの間で高度な自家製のプロトコルを使用しないでください。
理由はこれです-シミュレータがあるため、FPGA/ASICの「内部」でバグを見つけるのは簡単です。したがって、データが思い通りに届き、プログラムが送信するときにデータが消える場合は、ハードウェアユートピアに達しています。ソフトウェアレベルで作業できます:)(シミュレーターを使用)。しかし、もしあなたのデータがあなたに届かない場合、あなたがそれを望む方法で、そしてあなたはその理由を理解しなければなりません...あなたはラインに接続しなければならず、それはそれほど簡単ではありません。
回線上のバグを見つけることは、回線の状態をさまざまな時間で記録する特別な機器で回線に接続する必要があり、回線がプロトコルに従って動作することを確認する必要があるため、困難です。
2つの物理ユニットを接続する必要がある場合は、「プロトコル」をできる限り単純にします。プロトコルとは呼ばれなくなるところまでです。)たとえば、ユニットがクロックを共有している場合は、それらの間にxデータ線を追加します、そして一方のユニットにそれらを書き込み、もう一方のユニットに読み取りを行わせることで、たとえば、各クロックの立ち下がりでそれらの間にxビットを持つ1つの「ワード」を渡します。 FPGAを使用している場合、元のクロックレートがパラレルデータに対して速すぎる場合-実験によれば、これの速度を制御できます。たとえば、データを少なくとも「t」クロックサイクルなどのラインに留まらせます。 1つのユニットで単語を分割して別のユニットで再構成する必要なく、低いクロックレートで作業して同じパフォーマンスを得ることができるため、並列データ転送はより単純であると思います。 (うまくいけば、各ユニットが受け取る「クロック」の間に遅延はありません)。これでもおそらく複雑すぎる:)
SPI、I2Cなどについては、まだ実装していません。同じクロックで実行されている2つのFPGAのレッグを接続したと言えます(中央の抵抗の正確な構成を覚えていない)。より高いレートなので、FPGAが互いに非常に遠くに配置されていない限り、独自のFPGA間でデータを渡すための主な方法として、これらを使用する十分な理由を本当に考えることはできません。パラレルバスより。
[〜#〜] jtag [〜#〜] は一部のFPGA企業で製品のテスト/プログラミングに使用されていますが、高速でデータを転送する方法として使用されているかどうかは不明です。プロトコル...(まだいくつかの組み込みのオンチップサポートがあるかもしれません)。
既知のプロトコルを実装する必要がある場合は、このための既製のHDLコードを使用することを検討してください。