読者です 読者をやめる 読者になる 読者になる

FPGA開発日記

FPGAというより、コンピュータアーキテクチャかもね! カテゴリ別記事インデックス https://sites.google.com/site/fpgadevelopindex/

ReadyとValidを制御するためのSkid Buffer

f:id:msyksphinz:20160522024602j:plain

通常のデジタル回路設計において、特定のブロックとの信号をやり取りするのに、ReadyとValidを使うことができる。

Validは送信元がデータ送信を示すのに利用し、Readyは送信先のユニットがデータ受け入れ可能であることを示す。

ReadyとValidの制御については、以下のブログの記事が詳しい。僕もいつも参考にさせてもらっている。

ryuz.txt-nifty.com

ただし、この機構を使うと、すべてのパイプラインでreadyがスライスを切ることなく伝わってしまい、すべてのユニットに遅延が伝搬してしまう。

f:id:msyksphinz:20160522021701p:plain

f:id:msyksphinz:20160522021907p:plain

ユニット間でReadyとValidをいったん区切るためには、Skid Bufferというものを挿入する。これは、Readyがモジュールの逆方向に伝搬し、Readyの信号がパイプライン全体に広がって遅延を増大させることを防ぐ。

f:id:msyksphinz:20160522022307p:plain

Skid Bufferは、

  1. 信号の受け側からのReadyとValid
  2. 信号の送信側からの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を開くことができる。 このユニットの構造は大まかに以下のようになっている。

f:id:msyksphinz:20160522022924p:plain

受け側の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に戻し、送信元からのデータ受け入れを再開する。