論理回路デザイン
ArchiTek home page
ここで扱うFIFO

FIFOの基本的な原理

基本的なFIFOの設計

コード(RTL)

/* **************************** MODULE PREAMBLE ********************************

        Copyright (c) 2011, ArchiTek
        This document constitutes confidential and proprietary information
        of ArchiTek. All rights reserved.
*/

// ***************************** MODULE HEADER *********************************

module fifo (
        iVld,
        iStall,
        iData,

        oVld,
        oStall,
        oData,

        reset,
        clk

        );

// ************************ PARAMETER DECLARATIONS *****************************

        // 初期のパラメータ、上位モジュールで再定義のこと
        parameter               W       = 32;           // Data Length
        parameter               DR      = 2;            // Depth Radix

        // FIFOの深さ(2の累乗)を求める
        parameter               D       = 1<<DR;

// *************************** I/O DECLARATIONS ********************************

        // パイプライン入力、言及してきた信号名を合わせるためFullはStallに変更
        input                   iVld;
        output                  iStall;
        input   [W-1:0]         iData;

        // パイプライン出力、言及してきた信号名を合わせるためBusy(not Empty)はoVldに変更
        output                  oVld;
        input                   oStall;
        output  [W-1:0]         oData;

        // 一般的に必要なリセットとクロック
        // ユーザーによるソフトリセットを考慮して同期型のリセットを採用
        input                   reset;
        input                   clk;

// ************************** LOCAL DECLARATIONS *******************************

        reg                     iStall;
        wire                    iStallD;

        reg                     oVld;
        wire                    oVldD;

        // 入力ポインター、MSBは周期、その他はデータ位置を示す
        reg     [DR:0]          iPtr;
        wire    [DR:0]          iPtrD;

        // 出力ポインター、MSBは周期、その他はデータ位置を示す
        // 入力側の周期情報だけで足りるが、記述簡単のためMSBに周期情報を残す
        reg     [DR:0]          oPtr;
        wire    [DR:0]          oPtrD;

        // データ出力はラッチ、なお下記の配列memと同一データを管理する冗長性が存在します
        reg     [W-1:0]         oData;

        // 入出力パルス、EmptyおよびFullの場合は論理的にアサートしない
        wire                    iAlloc          = iVld & !iStall;
        wire                    oAlloc          = oVld & !oStall;

        // FIFOの中身はレジスタで構成、FPGAツールではたいていSRAMへ自動マッピング
        reg     [W-1:0]         mem[0:D-1];

// ****************************** MODULE BODY **********************************

// -----------------------------------------------------------------------------
// Data FIFO
// FIFOが空の場合は入力データが直接、そうでない場合は次のポインタが示すFIFOを出力FFにラッチ
// 事前にFFのD端子信号を用意する方法でデータをラッチ、遅延の移動を参照
always @(posedge clk)
        if (iAlloc & (iPtr[DR-1:0] == oPtrD[DR-1:0]))
                oData           <= #1 iData;
        else if (!oStall)
                oData           <= #1 mem[oPtrD[DR-1:0]];

// FIFOにデータを入力、ここはiPtrによる選択のため組み合わせ回路がどうしても挿入される
always @(posedge clk)
        if (iAlloc)
                mem[iPtr[DR-1:0]]
                                <= #1 iData;

// -----------------------------------------------------------------------------
// Data FIFO Pointer
// iStallはFull、oVldはBusy(not Empty)に相当
// 事前にFFのD端子信号を用意する方法でデータをラッチ、遅延の移動を参照
// ポインターはインクリメント型でいきなり+2になることはなく、=か!=を用いたピンポイント比較でよい
// ただし、FIFOポインタ内をランダムにアクセスする型は大小比較をする必要がある
always @(posedge clk)
        if (reset) begin
                iStall          <= #1 1'b0;
                oVld            <= #1 1'b0;
        end
        else begin
                iStall          <= #1 iStallD;
                oVld            <= #1 oVldD;
        end

always @(posedge clk)
        if (reset) begin
                iPtr            <= #1 {DR+1{1'b0}};
                oPtr            <= #1 {DR+1{1'b0}};
        end
        else begin
                iPtr            <= #1 iPtrD;
                oPtr            <= #1 oPtrD;
        end

// ポインタがちょうど一周すればFull(これ以上は受け付けることができない)
// Fullであっても出ていくデータがあればnot Fullに出来るがタイミングアークが切れなくなる(パス型
assign iStallD          = (iPtrD[DR] != oPtrD[DR])
                        & (iPtrD[DR-1:0] == oPtrD[DR-1:0]);

// ポインタが少しでも違えばBusy(not Empty)
assign oVldD            = (iPtrD != oPtrD);

// LintのWarning(Bit長不一致)を消すには、見にくくなるがiAlloc → {{DR-1{1'b0}}, iAlloc}
assign iPtrD            = iPtr + iAlloc;
assign oPtrD            = oPtr + oAlloc;

// ************************** FUNCTIONS and TASKS ******************************

endmodule

// *****************************************************************************
          

回路デザイン > 設計例 [FIFO] > ここで扱うFIFO    次のページ(Threshold対応FIFO)   このページのTOP ▲

[1]
パス型(S?の連結を組み合わせれば、2の累乗以外のFIFOも設計できます。FIFO深さが大きいと遅延に大きな影響を与えるのでそんなに使用することはないでしょう。

ただし、ポインター管理の部分を消去できるので、2,3段程度のFIFOでは積極的に利用した方がいいと思います。