これは、 FPGAsの resetsに関するシリーズの 3 番目で最後のページです。この前に最初の 2 つを読むことをお勧めします。
概要
resetsを作成するための適切な logic をセットアップするために時間をかけることは常に良い考えです。そのままの design に明らかな問題がなくても、 design でこの段階をスキップすると、犠牲になる可能性があります。 後で、 logic が適切に初期化されていないことが原因であることに気付かずに、不安定な問題を解決しようと何日も費やすかもしれません。このような問題を解決しようとする試みの中で、 design は問題の根本を理解せずに作成された厄介な回避策を蓄積しています。奇妙な不安定性に関するこのページの詳細。
プロジェクトの最初から reset signals を熟考して設計することも、新しい機能が追加されるにつれて reset signals が適切に成長していくことを保証するために重要です。 FPGA プロジェクトをゼロから開始する場合、多くの場合、そのコア機能が最初に実装され、その後、時間の経過とともに機能が追加されます。異なる modules には個別の clocks と resetsが必要になることが多いため、各部分について個別に何かを急いでまとめるという罠に陥るのは非常に簡単です。これにより、プロジェクトが進むにつれてますます混乱することがよくあります。
resets と clocksを含むために、初日から適切に作成された中央の moduleを用意することで、厄介なプロジェクトを回避する方が簡単です。また、以下でさらに説明するように、 reset controller と clock resources (必要に応じてPLLs と clock buffers ) は互いに影響を与えるため、それらを同じ module に配置すると効果があります。私は通常、この module に clkrst.vという名前を付けます。
ただし、 IP cores、サブシステム、または design blocks の一部が独自の resets および clocksのグループを生成する可能性があるため、これらすべてを 1 つの moduleに集中させることは不可能な場合がよくあります。このような場合、何が何に依存しているか、およびさまざまなソースから到着する resetsの要求に対してシステム全体がどのように反応するかについて、慎重に検討する必要があります。たとえば、 PCIe block への reset は、ほとんどの場合 bus 自体から到着し、 block は、この blockに接続されている logic で使用するために reset signal を生成します。このような状況では、たとえば、 PCIe bus から reset が到着した場合にシステム全体がどのように応答するか (まったく応答しない可能性も含む) を考慮する必要があります。
各プロジェクトには独自のストーリーがあるため、すべてのケースに対応できる単一のソリューションはありません。このページでは、概念について説明し、独自の reset controllerのビルディング ブロックとして使用できるアイデアとコード スニペットを提案します。ただし、これらのコード スニペットはプロジェクトに直接カット アンド ペーストするためのものではなく、デモンストレーションとして扱う必要があります。
簡単にするために、システム内の他の block が clocks も resetsも生成しないと仮定しますが、 controller を一般的なケースに拡張することはかなり簡単です。
reset state machine
ほとんどの designsでは、リセットが必要な主なシナリオが 2 つあります。
- クリーンなスタートを確実にするために、 FPGAの直後に powerup と bitstream configurationをリリースしました。
- pushbutton を押すか、 processor またはコンピューターからのコマンドによって、 reset が明示的に要求された場合。
さらに、 watchdog timers の有効期限が切れるか、その他の手段で主要なシステム障害が検出されたときに、リセットが必要になる場合があります。
これらすべてのシナリオに対して期待される対応は、根本的な再起動であり、何がうまくいかなかったとしても、それが修正されることを保証します。これは、開始された理由に関係なく、一貫性があり反復可能な reset sequence を保証する、ある種の state machineで行うのが最適です。
そうは言っても、ローカルで繰り返し発生する可能性のあるリセットが意味をなすシナリオもあります。たとえば、 video image frames を処理する logic は、各 frameの開始前にリセットできます。これには通常、軽量のメカニズムが必要であり、ローカル synchronous reset がアクティブ化されたときに、複数の registers に初期値を割り当てることになります。これは他のリセット メカニズムと同様であり、堅牢な操作を保証するためのクリーンかつシンプルな方法であることがよくあります。
しかし、この可能性についてはこれ以上付け加えることはあまりないので、このページの残りの部分では、 FPGA全体をカバーする基本的な resetに焦点を当てます。
不安定な clocks と resetの必要性
clocksを生成するために FPGA独自の PLLs を使用することは非常に一般的です (通常は推奨されます)。ただし、これらの PLLs は通常、 FPGA 上の他のすべての logic がアクティブになると同時に動作を開始します。その結果、これらの clocks に依存する logic には、通常よりも大幅に高い周波数を持つ不安定な clockが供給されます。
この場合、該当する logic paths の timing は保証されません。したがって、 PLLs によって生成された clocks に依存する logic は、 PLL がロックされるまで timing constraints を達成できなかったかのように扱われるべきです。
適切で一般的な解決策は、関連する PLL がロックされるまで、そのようなすべての logic を reset に保持することです。あるいは、この logic は、 PLL がロックされるまで clock を無視するように設定できます。たとえば、 flip-flopsの Clock Enable input (CE) が非アクティブであることを確認します。
外部 clock が FPGAの pin から logic elementsに直接接続されている場合、問題は clock generator (通常は PLL) が FPGA に bitstreamをロードしたときよりも速くロックするかどうかです。これを確認するのは必ずしも容易ではありません。
その結果、ほとんどの designsで synchronous elements の多くをリセットする必要があります。より正確には、不安定な clockのために reset が必要かどうかという問題について、これらの elements を 3 つのグループに分けることができます。
- garbage data を含む可能性があるもので問題ありません。
- clock が不安定である限り (たとえば、 clock enableのおかげで) 無視することが保証されているもの。
- リセットが必要なもの。
一部の FPGAs では configuration プロセス (つまり、 bitstream をロードして FPGAを初期化するプロセス) をセットアップできるため、すべての PLLs がロックされるまで FPGAのウェイクアップが遅延されます。これは、この問題を解決する方法になる可能性があります。このソリューションの欠点は、外部 clockに問題がある場合、 FPGA がまったく起動しないことです。このような状況は、非常に混乱する可能性があります。
シンプルな state machine
基本的な起動または再起動は非常にまれなイベントであるため、必要以上に数マイクロ秒かかっても問題ありません。多くの場合、 100 ms 程度まででも問題なく、これを利用できます。したがって、単純な counter は一連のイベントを実装する簡単な方法です。
最も単純な形式では、次のようになります。
reg [4:0] reset_count;
reg rst_src_pll, rst_src_shreg, rst_src_debounce;
reg clear_counter;
reg master_reset;
initial reset_count = 0;
initial master_reset = 1;
initial clear_counter = 1;
always @(posedge wakeup_clk)
begin
clear_counter <= rst_src_pll || rst_src_shreg || rst_src_debounce;
master_reset <= (reset_count != 31);
if (clear_counter)
reset_count <= 0;
else if (reset_count != 31)
reset_count <= reset_count + 1;
end
@rst_src_pll、 @rst_src_shreg 、および @rst_src_debounce は、システムをリセットするさまざまな理由を表しています。これらの registers は、他の logicによって値が与えられます。このような logicの例をいくつか見ていきますが、今のところ重要な点は、これらの registers が @wakeup_clk と同期していることです (したがって、 clock domain crossingは必要ありません)。
@clear_counter は、 resetの理由の logic OR です。この register は、 @reset_count をゼロに変更します。それ以外の場合、この counter は 0 から 31 (この例では) まで増加し、その後停止します。
最後に、 @reset_count がカウントを終了しない限り、 @master_reset はアクティブです。これは reset state machineの最も単純な形式であり、31 まで数えることも非常に控えめです。
したがって、 @rst_src_N signals のいずれかがアクティブである場合、たとえ 1 つの clock cycleであっても、 synchronous reset は 31 個の clock cyclesに対してアクティブになります。
長い reset pulseには 2 つの利点があります。 まず、関連する @rst_src_N がランダムにオンまたはオフになる場合 (たとえば、 PLL lock detectors、 push buttonsの揺れ、 resets を複数回要求するソフトウェア)、これらの複数のアクティベーションは可視の synchronous resetに伝達されません。通常、このような複数のアクティベーションは無害ですが、 output pinsの不要なアクティビティが発生する可能性があります。このような活動はマイナスの影響を与える可能性があります。たとえば、電子機器をテストする人を混乱させて、何かがおかしいと思い込ませることがあります。
そういう意味では、31 clock cycles の例はかなりミニマルです。そのような遅延が許容できる場合は、 10-100 msに対応する値までカウントすることをお勧めします。そうすることで、それより短いウォブルは reset controllerによって隠されます。
reset pulse が長くなる 2 つ目の理由は、元の synchronous reset をローカル コピーに配布する際に (前述のように)、1 つの clock cycleの遅延が発生することです。 logic 全体に reset を分散させるために信号を複数回コピーする必要がある場合、遅延の合計が長くなるだけでなく、不均一になる可能性もあります。長い reset pulse は、ある時点で、すべての logic がアクティブな synchronous resetに公開されることを保証します。 reset の非アクティブ化も不均一になるため、 reset pathで不均一な遅延を持つことは依然として悪い考えですが、問題がない場合もあります。この件に関しては、 reset pulse の 31 clock cycles はおそらく必要以上に長いですが、問題はありません。
他の clock domainsのResets
@master_reset は通常の synchronous resetですが、 application logicで使用される clocks とは異なる clock と同期されます。他の clocks用に synchronous resets を生成するには、各 clockに対して次のような操作を行う必要があります。
reg reset_clk_pre1, reset_clk_pre2;
reg reset reset_clk;
always @(posedge clk)
begin
reset_clk <= reset_clk_pre2;
reset_clk_pre2 <= reset_clk_pre1;
reset_clk_pre1 <= master_reset;
end
これは、 @reset_clkを生成する 3 段の通常の clock domain crossing です。この信号は、 @clkに付随する synchronous reset です。実際には 2 段階で十分ですが、これは重要な信号なので、余分な registerを追加して安全を確保しました。
reset controllerの clock
@wakeup_clk、つまり reset state machineとして使用できる clocks には、原則として次の 3 種類があります。
- FPGAの外部で生成され、 FPGA がウェイクアップしたときに安定していることが知られている clock 。
- FPGA上の PLL によって生成された clock は、 FPGA がウェイクアップしたときに準備ができているとは想定されていません。
- 一部の FPGAsでは、 FPGA 自体で ring oscillator によって生成された configuration clockを使用できます。
最初のオプションは、最も簡単に使用できます。 FPGAの PLLsを駆動する reference clock がほぼ常に存在するため、この reference clock は多くの場合、 wakeup clockとして直接使用できます。ただし、 FPGA が起動したときに clock が実際に安定していることを確認することが重要です。つまり、 FPGA が bitstream をロードするのにかかる時間が、外部 oscillator が有効な clockを生成するのにかかる時間よりも長いことです。 datasheetsを見ると、通常は大きなマージンでこのケースになります。ただし、 boardの powerup sequence が適切に計画されていない場合、 oscillator の supply voltage が正しいレベルに達するずっと前に、 FPGA が bitstream の読み取りを許可される可能性があります。
2 番目のオプションは、 FPGA 自体の PLL によって生成された clock を使用することです。明らかな利点は、この clock が application logic にも使用される可能性があるため、 powerだけでなく clock resources でもより効率的であることです。この選択では、 clock が安定するまで reset state machine を初期状態に保持する必要がありますが、これは次のようにして実行できます。
reg rst_src_pll;
reg rst_src_pll_pre;
initial rst_src_pll = 1;
initial rst_src_pll_pre = 1;
always @(posedge wakeup_clk)
begin
rst_src_pll <= rst_src_pll_pre;
rst_src_pll_pre <= !pll_locked;
end
@pll_locked は、 @wakeup_clk (active high) を生成する PLL の lock detector output です。このシグナルは非同期であるため、最初に @wakeup_clkと同期され、次に上記のように @clear_counterをアクティブにする理由の 1 つとして使用されます (つまり、 @rst_src_pllを使用)。
このオプションのもう 1 つの利点は、 reference clock が一時的に不安定になったり、存在しなくなったりした場合 (特に boardの電源を入れた後)、 lock detector も不安定になる可能性が高いことです。したがって、 @master_resetを非アクティブ化する前に @reset_count が大きな数 (31 よりはるかに大きいことは確実) をカウントすると、 reference clock が動作可能になるまで FPGA が reset のままになる可能性があります。ただし、これは当てにはなりません。
いずれにせよ、 @wakeup_clk が PLL の output であるという事実は、この clock が安定する前に logic にフィードすることを必然的に意味します。したがって、その期間中に state machine が適切に動作するかどうかは明らかではありません。ある時点で clock が十分に良くなり、適切な resets が生成されるため、これは問題ではないと主張することができます。 resetの後にすべてが過去に残されている場合、その前に何が起こったのか誰が気にしますか?
より厳密なアプローチは、 wakeup clock がロックされるまで resets を安定してアクティブにしておく必要があるため、 FPGA が bitstream configurationの直後に奇妙な動作をしないようにすることです。これは、この clockで非常に単純な logic のみを使用することに注意を払う必要があります。言い換えれば、 logic は、 clock が予想よりも高い周波数を持っていても、大幅に故障しないようなものでなければなりません。
@wakeup_clk の周波数が一時的に高すぎる場合に何が起こるかを分析するには、 @reset_count が vectorである reset state machine の唯一の register であることに注意してください。これは、他のすべての flip-flops が、 timingに違反しているため、最悪の場合、計算された "next value" 1 つの clock をサンプリングするのが遅すぎる可能性があることを意味します。特に、 PLL がロックされていないときに @pll_locked がローであるため、 @rst_src_pll はすぐに着実に高くなり、したがって @clear_counter も着実に高くなります。 flip-flop の D input (次の value) が変わらない場合、 clock がどれほど高速であっても問題ありません。
したがって、唯一の問題は @reset_countで、計算された next value が @clear_counterのためにゼロで安定するまで、誤ってカウントアップされる可能性があります。たとえば、現在の値が 3 (binary 011) の場合、次に計算される値は 4 (binary 100) です。ただし、2 つの LSBs が timingのためにサンプリングされず、3 番目の bit がサンプリングされた場合、 counterの値は代わりに 7 (111 binary) にジャンプする可能性があります。
これが起こらないようにするために、 @pll_locked から @clear_counter までの registers のチェーンの初期値はすべて、 @reset_count を安定してゼロに保持するように割り当てられます。したがって、 @wakeup_clk が安定するまで @pll_locked が安定してローのままである場合、 @reset_count はゼロから離れず、 @master_reset は安定してアクティブなままです。
最後のオプションとして、 reset controllerに FPGAの ring oscillator を使用するには: 私はそれを自分で試したことがないので、それがどれほど良いアイデアなのかわかりません。しかし、それが他に選択肢がなくて困っている人を救うのであれば、 Xilinxの FPGAsを使って多かれ少なかれそれを行う方法は次のとおりです。 FPGA の Configuration User Guide で STARTUPE2 (またはそのようなもの)と呼ばれる primitive を検索してください。 CFGMCLKという名前の output が必要です。これは、 FPGA 自体の不正確な ring oscillator からの clock です。その頻度は 50-65 MHz前後です。この clock は、 FPGA が起動したときに安定していることが保証されているため、 timing constraint をかなり高い周波数 (たとえば、 100 MHz) に設定します。
しかし、これは、本当に他に選択肢がない場合に私が行うことです.たとえば、 FPGA が起動したときに外部 reference clock が安定していない場合、 logicに追加の遅延を実装する必要があります。
PLLsのリセット
一般に、 reset sequenceの一部として PLLs をリセットすることをお勧めします。これにより、 reference clock が有効であることがわかっているときに確実にリセットされます。また、 reset がユーザーによって開始された場合 (たとえば、 reset pushbuttonを押す)、これは PLLの不十分なロックに起因する問題に対応している可能性があります。あってはならないことですが、万が一の場合に備えて。
@clear_counter は PLL がロックされなくなるとすぐにアクティブになるため、 PLLをリセットするために使用することはできません。これを使用した場合、 PLL は reset stateに残り、ロックされることはなく、 reset は解放されません。同じ理由で、 PLLsの resets は @reset_countから派生できません。 すべての PLLs がロックされている場合を除き、ゼロに保持されます。
解決策は、 @clear_counterに似た PLL用に別の reset register を作成することです。したがって、ロックされていない PLLs が @rst_src_pllに反映されるという上記の表記を使用すると、次のようになります。
reg clear_counter;
reg reset_plls;
initial clear_counter = 1;
initial reset_plls = 1;
assign reset_sources = rst_src_shreg || rst_src_debounce;
always @(posedge wakeup_clk)
begin
clear_counter <= rst_src_pll || reset_sources;
reset_plls <= reset_sources;
[ ... ]
このコード スニペットでは、 @rst_src_pll は @reset_sourcesから除外され、 @clear_counterにのみ使用されます。その結果、 PLLs は FPGA全体と共にリセットされますが、それ自体がロックされていない場合を除きます。
@reset_sources がランダムに Low と High に切り替わると、ここに示されているコードに従って @reset_plls も変わることに注意してください。 reset が狂ったようにオンとオフを繰り返すとき、 PLLs に悪いことは何も起こらないので、これは通常無害です。ただし、次に説明するように、これを回避する方法もあります。
より複雑な起動シーケンス
単純な counter (@reset_count) を state variable として使用すると、より複雑な startup sequencesを簡単に実装できます。たとえば、 clocks をオフにしてアクティブにする適切な asynchronous resetsを生成するのは非常に簡単です。 これは、 clocks がオフになっているときと resets がアクティブになっているときのタイムスロットを定義する単純な logic expressions で行われます。
したがって、この単純な counter メソッドは、プロジェクトの開始時に reset state machine からの単純なニーズがあるように見える designs の場合でも、適切な出発点となります。後で複雑な startup sequence が必要であることが判明した場合、この目標を達成するために既存の logic を拡張するのは簡単です。
いずれにせよ、 startup sequence の計画は、 sequence の各フェーズが有効になる期間を定義することに要約されます。そのような各期間は、 @reset_count が持つべき値の範囲に変換されます。
たとえば、 design に関連のない 2 つ以上の clocksがある場合、上記のように各 clock domain に対して reset signals を作成できます (「他の clock domainsに対するResets 」を参照)。ただし、この方法を採用すると、各 clock domains は事実上ランダムな順序で reset から出てきます。これは通常は問題になりませんが、問題になる場合は、 @reset_countの進行状況に基づいて、各 clock domain の reset が定義された時間に非アクティブ化される可能性があります。
複数の counterを実装することもできます。これは、 reset sequence が続行する前に特定の条件が満たされるのを待つ必要がある場合に便利です。たとえば、 reset sequence で PLLsをリセットし、ロックされるまで待機してから reset sequenceを続行する場合、すべての PLLs がロックされるまでゼロに保持される 1 つの counter があると便利です。2 番目の counter は、最初の counter のカウントが終了するまでゼロに保持されます。
PLL がその lockを失った場合、 PLLs 自体はリセットされませんが、それらに依存するすべてがリセットされることに注意してください。 lock を失った PLL は、ほとんどの designsで重大な障害になるため、これは望ましい動作ではない可能性があります。 lockが失われた場合に完全な reset を要求するには、以下に定義されているように @pll_restart を OR と組み合わせて @reset_sourcesを取得する信号に追加します。
assign pll_restart = rst_src_pll && !master_reset;
これは単に次のように述べています。 master reset が非アクティブになった後に PLL のロックが解除された場合は、 PLLsを含むすべてを再度リセットします。これが機能するためには、 reset count は lock detectorsの可能性のあるぐらつきに耐えるのに十分な長さである必要があります。つまり、 PLL がまだロックされていなくても、 reset count は、 PLLの lock detector が高くなる時間より長くなければなりません。これは、 PLL が lockを取得するのにかかる時間と混同しないでください。一部の lock detectors はまったくぐらつきません。これらのぐらつきは、 PLLの lock time よりもかなり短い可能性があります ( datasheetで指定)。
wakeup shift register
少し overkillかもしれませんが、私は通常、この種の wakeup shift register を designsに追加します。
reg [15:0] wakeup_shift;
reg rst_src_shreg;
initial rst_src_shreg = 1;
initial wakeup_shift = 0;
always @(posedge wakeup_clk)
begin
rst_src_shreg <= !wakeup_shift[15];
wakeup_shift <= { wakeup_shift, 1'b1 };
end
ほとんどの FPGAs は @wakeup_shift を shift register primitiveとして実装しており、これは LUTと同等のリソースを消費するため、リソースが安く、 powerup中に reset が発生するようにする別のメカニズムを提供します。これは、 PLLsのない design で必要です。他には @clear_counterをアクティブ化するものがないためです。ただし、 PLLsがあっても、 FPGA が起動したときにすでにロックされている可能性があります。これは、一部の FPGAsの bitstream configuration で可能なオプションです。
いずれにせよ、これは推奨されるアドオンです。転ばぬ先の杖。
外部 reset button
Reset buttons は非常に一般的です。それらが行うことは、 design ごとに異なります。 1 つの可能性は、ユーザーが「reset」と見なす button が FPGA pin に接続され、 bitstream を FPGAにロードするプロセスを開始することです。 embedded processorがある FPGAs で、 processorの reset pinに接続することもできます。
そして、この reset button は、 FPGA logicをリセットする目的で、 FPGA上の一般的な I/O pin に接続できます。この場合、 @clear_counterを有効にするもう 1 つの理由です。
@reset_count が 10 ms 以上に対応する数にカウントされる場合、 counter 自体によってウォブルが吸収されるため、 input pinからの信号の debounce は必要ありません。この場合、これで十分です。
reg rst_src_debounce;
reg rst_src_debounce_pre;
initial rst_src_debounce = 1;
initial rst_src_debounce_pre = 1;
always @(posedge wakeup_clk)
begin
rst_src_debounce <= rst_src_debounce_pre;
rst_src_debounce_pre <= reset_button_pin;
end
ただし、 counter がすぐに終了する場合 (上記の例に示すように、 31に到達するまで)、 pushbutton には debouncingが必要です。これを行うには、いくつかの方法があります。たとえば、次のとおりです。
reg [17:0] debounce_count = 0;
reg reset_button_d, reset_button_d2, reset_button_d3;
wire debounce_reached = (debounce_count == 250000);
initial debounce_count = 0;
initial rst_src_debounce = 1;
always @(posedge wakeup_clk)
begin
reset_button_d3 <= reset_button_d2;
reset_button_d2 <= reset_button_d;
reset_button_d <= reset_button_pin;
if (reset_button_d2 != reset_button_d3)
debounce_count <= 0;
else if (!debounce_reached)
debounce_count <= debounce_count + 1;
if (debounce_reached)
rst_src_debounce <= reset_button_d3;
end
これは比較的厳密な debouncerであり、ノイズの多い input signalsとはうまく連携しません。これは、ニーズに応じて利点にも欠点にもなります。
このコード例は、 25 MHz clock用に書かれています。 @reset_button_pin が 10 msの間に同じ値を持っていた場合、 @reset_button_pin の値は @rst_src_debounce にコピーされます。 @reset_button_d3 が値を変更するときと同じ clock cycle で、 @debounce_count がゼロに変更されることに注意してください。したがって、 @reset_button_d3 が値を変更すると、すぐに @rst_src_debounce にコピーされることはなく、同じ値を長期間維持した後にのみコピーされます。
概要
FPGAの初期化を設計する際には、考慮すべきことがたくさんあります。このページではいくつかの概念とアイデアを紹介しましたが、実際のタスクは、アクションを開始する必要があるイベントを正しく認識することであることに留意することが重要です。 logic を確実に稼働状態にするために、そのような各イベントに対する正しい応答を定義することも重要です。