通常のデジタル回路設計において、特定のブロックとの信号をやり取りするのに、ReadyとValidを使うことができる。
Validは送信元がデータ送信を示すのに利用し、Readyは送信先のユニットがデータ受け入れ可能であることを示す。
ReadyとValidの制御については、以下のブログの記事が詳しい。僕もいつも参考にさせてもらっている。
ただし、この機構を使うと、すべてのパイプラインでreadyがスライスを切ることなく伝わってしまい、すべてのユニットに遅延が伝搬してしまう。
ユニット間でReadyとValidをいったん区切るためには、Skid Bufferというものを挿入する。これは、Readyがモジュールの逆方向に伝搬し、Readyの信号がパイプライン全体に広がって遅延を増大させることを防ぐ。
Skid Bufferは、
- 信号の受け側からのReadyとValid
- 信号の送信側からのReadyとValid
の信号を受け、もし受け側が受け入れられない(Readyが0)の場合は、内部のストレージに信号をバックアップしておく機能を持っている。
このデザインについて、ALTERAの資料がVerilogのデザインとともに提供されている。
https://www.altera.com/content/dam/altera-www/global/en_US/pdfs/literature/manual/stx_cookbook.pdf
cookbookという圧縮ファイルをダウンロードすると、cookbokk/stogage/ready_skid.v
を開くことができる。
このユニットの構造は大まかに以下のようになっている。
受け側のReadyが0(受け入れられない)場合に送信要求が来た場合
受信側は受け入れられないので、そのままready_iにready_oが伝わり、SkidBufferにそもそもデータは受け入れられない。
ready_i <= ready_o;
送信元からValidによりデータを受け入れたのだが、その後すぐに受け入れ側のReadyが落ちた場合は、次の送信側のValidをバックアップストレージに格納する。
if (internal_ready_i && valid_i) begin // must accept data from source if (ready_o || !internal_valid_o) begin // accept to main registers valid_o <= 1'b1; internal_valid_o <= 1'b1; dat_o <= dat_i; end else begin // accept to backup storage backup_valid <= 1'b1; backup_storage <= dat_i; ready_i <= 1'b0; // stop stop! internal_ready_i <= 1'b0; end end
上記のVerilogデザインでは、ready_o(受信側のReady信号)が1になっている場合はバックアップストレージを使用せずにそのまま1回スライスを挟んで受信側にデータを送信する。 そうでない場合は、一旦backup_storageにデータを格納し、backup_validを1に設定してready_oが再び立ち上がるのを待つ。
backup_storageにデータが格納されている状態でready_oが立ち上がった場合
ready_oが立ち上がったときに、backup_storageにデータが入っている場合はそれを吐き出す。
if (internal_valid_o & ready_o) begin // main data is leaving to the sink if (backup_valid) begin // dump the backup word to main storage backup_valid <= 1'b0; dat_o <= backup_storage; valid_o <= 1'b1; internal_valid_o <= 1'b1; if (ready_i && valid_i) begin $display ("ERROR: data lost in skid buffer"); end end
そうでない場合は、ready_iを1に戻し、送信元からのデータ受け入れを再開する。