論理回路デザイン
ArchiTek home page
コーディング

コード(RTL)

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

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

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

module cache (
        iReq, iGnt, iAddr,
        iRdStrb, iRdAck, iRdData,

        oRdReq, oRdGnt, oRdAddr,
        oRdStrb, oRdAck, oRdData,

        aOpReq, aOpGnt,

        dramWE, dramWA, dramWD, dramRE, dramRA, dramRD,

        reset, clk

        );

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

        // LLRにはキャッシュライン数を、BLRにはバースト長を設定する
        parameter               LLR     = 2,            // Cache Line Length Radix
                                BLR     = 2;            // Burst Length Radix

        parameter               LBR     = LLR+BLR;

        parameter               LL      = 1<<LLR;
        parameter               BL      = 1<<BLR;

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

        // Master Address Interface
        // マスターインターフェイスのRequest信号グループ(ハンドシェークを実施)
        input                   iReq;
        output                  iGnt;
        input   [31:0]          iAddr;

        // Master Read Data Interface
        // マスターインターフェイスのRead信号グループ、キャッシュデータとしてSRAMから直接出力
        input                   iRdStrb;
        output                  iRdAck;
        output  [31:0]          iRdData;

        // External Memory Read Address Interface
        // 外部メモリインターフェイスのRequest信号グループ(ハンドシェークを実施)
        output                  oRdReq;
        input                   oRdGnt;
        output  [31:0]          oRdAddr;

        // External Memory Read Data Interface
        // 外部メモリインターフェイスのRead信号グループ(バースト長分のハンドシェークを実施)
        output                  oRdStrb;
        input                   oRdAck;
        input   [31:0]          oRdData;

        // Asynchronous Interface
        // タグ操作信号グループ(ハンドシェークを実施)、クリアだけの機能なので引数なし
        input                   aOpReq;
        output                  aOpGnt;

        // Data RAM Port (Dual Port)
        // データSRAMのインターフェイス、ReadとWriteの2ポートで深さはパラメータに示した通り
        output                  dramWE;
        output  [LLR+BLR-1:0]   dramWA;
        output  [31:0]          dramWD;
        output                  dramRE;
        output  [LLR+BLR-1:0]   dramRA;
        input   [31:0]          dramRD;

        // Utility
        // 単一クロック制御
        input                   reset;
        input                   clk;

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

        // Tag Control
        // タグのValidフラグと上位アドレス情報、WriteがないのでModifyフラグなし
        // キャッシュライン数分必要でWayがあるならその積の分量を用意(ここではFFとして用意)
        reg     [LL-1:0]        vldFlag;
        reg     [31:LBR+2]      addrTable[0:LL-1];
        wire                    eAdVld;         // 指定するキャッシュラインのValid値
        wire    [31:LBR+2]      eAdTblRef;      // 指定するキャッシュラインの上位アドレス
        wire                    eAdBusyHit;     // 入力信号と上記の一致を示す(キャッシュヒット)

        // Operation Flag Control
        // キャッシュラインの位置を示す、入力アドレスの該当部分をそのまま代入
        wire    [LBR+1:BLR+2]   eOpIndex;

        // Status Control
                                                // synopsys translate_off
        reg     [39:0]          opStat;         // synopsys translate_on     デバッグ用(ASCII)
        reg     [3:0]           opMaster;       // 状態で変化するタグ・マスター制御(下記4信号)
        wire                    opGnt, opPush, opVldSet, opVldClr;
        reg     [2:0]           opStart;        // 状態で変化するFIFO・メモリ制御(下記3信号)
        wire                    opRdRqStart, opRdRtStart, opRdExStart;
        wire    [2:0]           opAck;          // 上記opStart信号に対するAck
        wire                    eOpAlloc;       // キャッシュ操作の成否
        wire                    eOpVldSet;      // キャッシュ操作時のValidフラグセット指示
        wire                    eOpVldClr;      // キャッシュ操作時のValidフラグクリア指示
        wire                    eOpPush;        // キャッシュ操作時のアドレスタグ書き戻し指示
        wire                    eOpRdRqStart, eOpRdRtStart, eOpRdExStart;
                                                // キャッシュ操作時のFIFO・メモリ制御指示
        // Read Request
        wire                    eRdRqGnt;       // 外部メモリのGrant

        // Read Route FIFO (Depth=2)
        // Routing FIFOの深さは2固定、入力1に対して出力はバースト分の割合(下記Cntを使用)でFIFO操作
        // FIFOの内容を途中チェックするため、一般的なFIFOモジュールをコールしない
        // eRd*は入力側の信号、rRdは出力側の信号を表す
        // FIFOは2次元でなく1次元表記(2次元配列のセンシビリティリスト記述は柔軟性が問題なため)
        reg     [LLR*2-1:0]     rdRtIndexFIFO;  // FIFO本体、以下フラグとポインター
        reg                     eRdRtFull, rRdRtBusy;
        wire                    eRdRtFullD, rRdRtBusyD;
        reg     [1:0]           eRdRtPtr, rRdRtPtr;
        wire    [1:0]           eRdRtPtrD, rRdRtPtrD;
        reg     [BLR-1:0]       rRdRtCnt;       // バーストをカウントするための変数
        wire    [BLR-1:0]       rRdRtCntD;
        wire                    eRdRtReq, rRdRtReq;
        wire                    eRdRtGnt, rRdRtGnt;
        reg     [LBR+1:BLR+2]   rRdRtIndex;     // FIFO情報(キャッシュラインのアドレス)
        wire    [BLR+1:2]       rRdRtWord;      // FIFO情報(キャッシュライン内のワード位置)
        wire                    eRdRtAlloc, rRdRtAlloc;
        wire                    rdRtBusy;       // 判定部で使用するFIFOの状態、Full, Emptyだけでなく
                                                // FIFOの内容と入力信号をチェックしたもの

        // Read Strobe
        // 外部メモリのデータの状態を示す、外部信号をそのまま代入
        wire                    rRdStReq;
        wire    [31:0]          rRdStData;

        // Read Execution FIFO (not implemented)
        // Execution FIFOは、本来Non-blockingアクセスのため実装するが、あえて抜いている
        // 判定部(eRd*信号)とSRAM調停部(rRd*信号)を直結する
        wire                    eRdExReq, rRdExReq;
        wire                    eRdExGnt, rRdExGnt;
        wire    [LBR+1:BLR+2]   rRdExIndex;
        wire    [BLR+1:2]       rRdExWord;

        // RAM Arbiter
        // SRAM調停部の信号、SRAM読み出しは1クロックかかるので、Ackはレジスタにして遅延させる
        reg                     mOpRdOtStart;
        reg                     mOpRdOtStartD;
        reg                     rOpRdRqAck, rOpRdDtAck;
                                // 以下、基本的にこのままSRAM信号になる
        reg                     ramWrReq, ramRdReq;
        reg     [LBR+1:BLR+2]   ramWrIndex, ramRdIndex;
        reg     [BLR+1:2]       ramWrWord, ramRdWord;
        reg     [31:0]          ramWrData;

        // RAM Pipe Control
        // SRAM出力はマスターに接続するため、マスターのデータ受付けの許可信号(Stallの反転)を作る
        wire                    rOpGnt;

        // Utility
        // for()文で使用
        integer                 i;

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

// *****************************************************************************
//                              Flag Control
// *****************************************************************************

// -----------------------------------------------------------------------------
// Tag Control
// Validフラグは同期リセットとクリア信号(タグ操作インターフェイスが影響)により全てクリア
// セット信号により該当するキャッシュラインのValidフラグのみセット
always @(posedge clk)
        if (reset | eOpVldClr) for (i=0; i<LL; i=i+1)
                vldFlag[i]      <= #1 1'b0;
        else if (eOpVldSet)
                vldFlag[eOpIndex]
                                <= #1 1'b1;

// アドレス情報はクリアする必要がないので、Validフラグがセットされるタイミングでセットするのみ
always @(posedge clk)
        if (eOpPush)
                addrTable[eOpIndex]
                                <= #1 iAddr[31:LBR+2];

assign eAdVld           = vldFlag[eOpIndex];
assign eAdTblRef        = addrTable[eOpIndex];

// 最終的なキャッシュヒット信号
assign eAdBusyHit       = eAdVld & (iAddr[31:LBR+2] == eAdTblRef);

// -----------------------------------------------------------------------------
// Asynchronous Flush Return
// タグ操作のGrant(許可)は判定部が出すクリア信号を代用する
// 今回インターフェイスと判定部は直結したため、クリア信号自体タグ操作のRequestが関与する
// aOpReq→opVldClr(クリア信号)→aOpGntなので、外部でaOpGnt→aOpReqの組み合わせ回路は厳禁
assign aOpGnt           = opVldClr;

// *****************************************************************************
//                              Cache Control
// *****************************************************************************

// -----------------------------------------------------------------------------
// Operation Address Definition
assign eOpIndex         = iAddr[LBR+1:BLR+2];

// -----------------------------------------------------------------------------
// Encode Type of Status
// 判定部: Writeがないため簡単なステートマシンになる
// マスターよりタグ操作のRequestを優先し、キャッシュクリアを先行させる
// 簡単化しているため、ValidフラグではなくeAdBusyHit(キャッシュヒット)が状態判定のキーになる
always @(
        aOpReq or
        eAdBusyHit or
        rdRtBusy
        )
        casex ({aOpReq, eAdBusyHit, rdRtBusy})
                // キャッシュミス時は外部メモリに対しデータフェッチを指示する
                // Routing FIFO内に同じアドレスのRequestがあると(rdRtBusy=1)、
                // 外部メモリ2度読みなるため、これをブロックする(Stallになるが2度読みよりまし)
                3'b0_0_0: begin                         // synopsys translate_off
                        opStat          = "Fetch";      // synopsys translate_on
                        opMaster        = 4'b0110;
                        opStart         = 3'b110;
                end
                // キャッシュヒット時はSRAMをReadしマスターに出力させる
                // フェッチと同様、SRAMにデータが格納するまではブロックする
                3'b0_1_0: begin                         // synopsys translate_off
                        opStat          = " Read";      // synopsys translate_on
                        opMaster        = 4'b1000;
                        opStart         = 3'b001;
                end
                // タグ操作のRequestがある場合、全てに優先して処理する(単純にクリア信号を作る)
                3'b1_x_0: begin                         // synopsys translate_off
                        opStat          = " Clr ";      // synopsys translate_on
                        opMaster        = 4'b0001;
                        opStart         = 3'b000;
                end
                // Requestなし、もしくはRead待機(メモリフェッチが完了しヒット状態になるまで)を示す
                default: begin                          // synopsys translate_off
                        opStat          = " NOP ";      // synopsys translate_on
                        opMaster        = 4'b0000;
                        opStart         = 3'b000;
                end
        endcase

// 判定した結果をタグ・マスター制御信号に代入
assign {opGnt, opPush, opVldSet, opVldClr}
                        = opMaster;

// 判定した結果をFIFO・メモリ制御信号に代入
assign {opRdRqStart, opRdRtStart, opRdExStart}
                        = opStart;

// FIFO・メモリの状態信号を束ねる
assign opAck            = {eRdRqGnt, eRdRtGnt, eRdExGnt};

// -----------------------------------------------------------------------------
// All OK
// FIFO・メモリ制御と状態が合致すれば、キャッシュ操作の実行になる
assign eOpAlloc         = &(~opStart | opAck) & iReq;

// -----------------------------------------------------------------------------
// Dispatch Signals of Master
// マスターのGrantには、タグ・マスター制御とFIFO・メモリ制御と状態が合致がダイレクトに伝わる
// Writeが加わる複雑な状態制御になると、深度の大きい組み合わせ回になり動作周波数のボトルネックになる
assign iGnt             = &(~opStart | opAck) & opGnt;

// タグ・マスター制御パルスを作る、eOpVldClrは特殊なため不要(複雑な状態制御になるとNG)
assign eOpPush          = eOpAlloc & opPush;
assign eOpVldSet        = eOpAlloc & opVldSet;
assign eOpVldClr        = opVldClr;

// -----------------------------------------------------------------------------
// Dispatch Signals of Memory
// FIFO・メモリ制御パルスを作る
assign eOpRdRqStart     = eOpAlloc & opRdRqStart;
assign eOpRdRtStart     = eOpAlloc & opRdRtStart;
assign eOpRdExStart     = eOpAlloc & opRdExStart;

// *****************************************************************************
//                              Read Memory FIFO
// *****************************************************************************

// -----------------------------------------------------------------------------
//      Read Request
// -----------------------------------------------------------------------------
// 判定部の信号が外部メモリにダイレクトに伝わる、また入力アドレスと出力アドレスはパススルーする
assign oRdReq           = eOpRdRqStart;
assign oRdAddr          = {iAddr[31:BLR+2], {BLR+2{1'b0}}};

assign eRdRqGnt         = oRdGnt;

// -----------------------------------------------------------------------------
//      Read Route FIFO (Depth=2)
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// FIFO Control
// Routing FIFO: 一般的なFIFOの記述と同じ、ただし内容を参照するためこのモジュール内に展開
always @(posedge clk)
        if (reset) begin
                eRdRtFull       <= #1 1'b0;
                eRdRtPtr        <= #1 2'h0;
                rRdRtBusy       <= #1 1'b0;
                rRdRtPtr        <= #1 2'h0;
                rRdRtCnt        <= #1 {BLR{1'b0}};
        end
        else begin
                eRdRtFull       <= #1 eRdRtFullD;
                eRdRtPtr        <= #1 eRdRtPtrD;
                rRdRtBusy       <= #1 rRdRtBusyD;
                rRdRtPtr        <= #1 rRdRtPtrD;
                rRdRtCnt        <= #1 rRdRtCntD;
        end

assign eRdRtFullD       = (eRdRtPtrD[1] != rRdRtPtrD[1])
                        & (eRdRtPtrD[0] == rRdRtPtrD[0]);
assign rRdRtBusyD       = (eRdRtPtrD != rRdRtPtrD);

assign eRdRtPtrD        = eRdRtPtr + {1'h0, eRdRtAlloc};

// rRdRtCntでバースト分を数え、カウントアップしたものをFIFOポインターにする
assign {rRdRtPtrD, rRdRtCntD}
                        = {rRdRtPtr, rRdRtCnt} + {{BLR+1{1'b0}}, rRdRtAlloc};

assign eRdRtAlloc       = eRdRtReq & eRdRtGnt;
assign rRdRtAlloc       = rRdRtReq & rRdRtGnt;

// -----------------------------------------------------------------------------
// FIFO Body
// FIFOが1次元配列なので、for()文を使って2次元配列の等価な代入を実施
always @(posedge clk)
        if (eRdRtAlloc) for (i=0; i<LLR; i=i+1)
                rdRtIndexFIFO[eRdRtPtr[0]*LLR+i]
                                <= #1 eOpIndex[BLR+2+i];

// -----------------------------------------------------------------------------
// FIFO Signal
// FIFO制御は判定部が与え(eRdRtReq)、FIFO状態が判定部に返る(eRdRtGnt)
assign eRdRtReq         = eOpRdRtStart;
assign eRdRtGnt         = !eRdRtFull;

// FIFOの出口はSRAM調停部に接続する
assign rRdRtReq         = rRdRtBusy;
assign rRdRtGnt         = rOpRdRqAck;
assign rRdRtWord        = rRdRtCnt;

// FIFOが1次元配列なので、for()文を使ってFIFOの出口のデータを作る
always @(
        rdRtIndexFIFO or
        rRdRtPtr
        )
        for (i=0; i<LLR; i=i+1)
                rRdRtIndex[BLR+2+i]
                                = rdRtIndexFIFO[rRdRtPtr[0]*LLR+i];

// -----------------------------------------------------------------------------
// Read Busy Flag on Operation
// Routing FIFO内に入力アドレスと同じアドレスのものがあることを判定部に示す
assign rdRtBusy         = |rdRtBusyFunc(eRdRtPtr, rRdRtPtr, eOpIndex, rdRtIndexFIFO);

// -----------------------------------------------------------------------------
//      Read Strobe
// -----------------------------------------------------------------------------
// 外部メモリから返ってくるデータを調停部に渡す
assign rRdStReq         = oRdAck;
assign rRdStData        = oRdData;

assign oRdStrb          = rOpRdRqAck;

// *****************************************************************************
//                              Read Data FIFO
// *****************************************************************************

// -----------------------------------------------------------------------------
//      Read Execution FIFO (not implemented)
// -----------------------------------------------------------------------------

// Non-blockingアクセスを可能にするExecution FIFOは実装しないが、実装する場合はFIFOの実体を加える
// ただしRouting FIFOで実施したように、FIFO内の同一アドレスのチェックが必要になる

// -----------------------------------------------------------------------------
// FIFO Signal
// To prevent pipe stall which causes memory write fail to fill cache line,
// the request is masked by next pipe full.
// FIFO制御は判定部が与え(eRdExReq)、FIFO状態が判定部に返る(eRdExGnt)
assign eRdExReq         = eOpRdExStart;
assign eRdExGnt         = rRdExGnt;

// FIFOの出口はSRAM調停部に接続する
assign rRdExReq         = eRdExReq;
assign rRdExGnt         = rOpRdDtAck;
assign rRdExIndex       = iAddr[LBR+1:BLR+2];
assign rRdExWord        = iAddr[BLR+1:2];

// -----------------------------------------------------------------------------
//      Read Output FIFO (Depth=0)
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// FIFO Rename
// 調停部の信号がマスターインターフェイスにダイレクトに伝わる、またデータはSRAM出力になる
assign iRdAck           = mOpRdOtStart;
assign iRdData          = dramRD;

// *****************************************************************************
//                          SRAM Control (for Dual Type)
// *****************************************************************************

// -----------------------------------------------------------------------------
//      RAM Arbiter
// -----------------------------------------------------------------------------

// 調停部は2ポートSRAMなのでReadとWriteに分離できる
// 基本的に競合が生じない、生じる場合はシングルポートもしくはマスターWriteをサポートする場合になる

// -----------------------------------------------------------------------------
// Write Port
// SRAM Writeは外部メモリからデータを取得する場合に発生する
// rOpGnt信号はマスターがデータ受け取れるかどうかを示すが、これが受け取れない場合
// 未読部分への書き込みの恐れがあるため処理をブロックする
// Writeなので変数は組み合わせ回路のみになる
always @(
        rOpGnt or
        rRdRtIndex or rRdRtWord or
        rRdStReq or rRdStData
        ) begin

        rOpRdRqAck      = 1'b0;

        ramWrReq        = 1'b0;
        ramWrIndex      = {LLR{1'bx}};
        ramWrWord       = {BLR{1'bx}};
        ramWrData       = {32{1'bx}};

        if (rOpGnt)
                if (rRdStReq) begin     // Write (Memory -> SRAM)
                        // Ack
                                rOpRdRqAck      = 1'b1;
                        // SRAM Operation
                                ramWrReq        = 1'b1;
                                ramWrIndex      = rRdRtIndex;
                                ramWrWord       = rRdRtWord;
                                ramWrData       = rRdStData;
                end
end

// -----------------------------------------------------------------------------
// Read Port
// SRAM Readはマスターへのデータの返送時に発生する
// rOpGnt信号がアサートしないとWrite同様ブロック信号になる(単純なパイプラインStall)
// Readデータは1クロック遅延するため、マスターへのAck(mOpRdOtStart)はFFになる記述にする
always @(
        rOpGnt or
        rRdExReq or rRdExIndex or rRdExWord or
        mOpRdOtStart
        ) begin

        mOpRdOtStartD   = mOpRdOtStart;

        rOpRdDtAck      = 1'b0;

        ramRdReq        = 1'b0;
        ramRdIndex      = {LLR{1'bx}};
        ramRdWord       = {BLR{1'bx}};

        if (rOpGnt) begin
                if (rRdExReq) begin     // Read (SRAM -> Internal)
                        // Read Output Pipe Routing
                                mOpRdOtStartD   = 1'b1;
                        // Ack
                                rOpRdDtAck      = 1'b1;
                        // SRAM Operation
                                ramRdReq        = 1'b1;
                                ramRdIndex      = rRdExIndex;
                                ramRdWord       = rRdExWord;
                end
                else begin              // default case
                        // Read Output Pipe Routing
                                mOpRdOtStartD   = 1'b0;
                        // Ack
                                rOpRdDtAck      = 1'b1;
                end
        end
end

// このFFとSRAMのデータ出力が同期する
always @(posedge clk)
        if (reset)
                mOpRdOtStart    <= #1 1'b0;
        else
                mOpRdOtStart    <= #1 mOpRdOtStartD;

// -----------------------------------------------------------------------------
//      RAM Pipe Control
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// FIFO Signal
// マスターのデータパイプラインのGrant(Stallの反転)
assign rOpGnt           = iRdStrb | !iRdAck;

// -----------------------------------------------------------------------------
// FIFO Rename (SRAM Access Signal)
// 単純に調停部で生成した信号をSRAMに渡す
assign dramWE           = ramWrReq;
assign dramWA           = {ramWrIndex, ramWrWord[BLR+1:2]};
assign dramWD           = ramWrData;

assign dramRE           = ramRdReq;
assign dramRA           = {ramRdIndex, ramRdWord[BLR+1:2]};

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

// FIFO内のアドレスを入力値で検査して、一致するものはないかチェックする(それぞれ格納ごとに出力)
function [1:0] rdRtBusyFunc;
        input   [1:0]           iptr;
        input   [1:0]           optr;
        input   [LBR+1:BLR+2]   idx;
        input   [LLR*2-1:0]     iplane;
        reg     [LLR-1:0]       iextract;
        integer                 i, j;

        // FIFOに格納可能な数を全て走査
        for (i=0; i<2; i=i+1) begin
                // 準備として1次元配列の入力値から必要な格納値を抜き出す
                for (j=0; j<LLR; j=j+1)
                        iextract[j]     = iplane[i*LLR+j];

                // 入出力ポインターを見てデータが有効かどうかと、値の一致を調べる
                rdRtBusyFunc[i] = ((iptr[1] ^ optr[1])
                                        ? (i[0] < iptr[0]) | (i[0] >= optr[0])
                                        : (i[0] < iptr[0]) & (i[0] >= optr[0])
                                        )
                                & (idx == iextract);
        end
endfunction

endmodule

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

回路デザイン > 設計例 [キャッシュ] > コーディング    次のページ(テスト)   このページのTOP ▲