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

コード(sdcCntl RTL)

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

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

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

module sdcCntl (
        iReq, iGnt, iRxw, iAddr,
        pReq, pGnt, pAddr,

        wrPush, rdPush,

        cs_n, ras_n, cas_n, we_n, addr, ba,

        reg_pCOM, reg_pACCW, reg_pACCR,
        reg_pFAW, reg_pRRD, reg_dTWR, reg_dTRW,
        reg_dWL, reg_dRL,
        rdWL, rdRL,

        clk, reset_n

        );

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

        // Rowアドレスのスタートを定める(上位モジュールで設定)
        parameter       ROWS    = 5'h00;                // Row Address Start Bit

        // 状態は高機能版からシュリンクしたため冗長(圧縮可能だが参考に)
        parameter       IDLE    = 5'h00,                // Idle
                        REDY    = 5'h01,                // Ready to PREP
                        PREP    = 5'h02,                // Prepare to PREV
                        PREV    = 5'h03,                // Previous to DIRC
                        DIRC    = 5'h08,                // Direct Command
                        ABRT    = 5'h09,                // Abort
                        WACT    = 5'h10,                // Write Activate
                        WVIR    = 5'h11,                // Write Activate Virtual
                        WNUL    = 5'h12,                // Write Activate Null
                        WEND    = 5'h13,                // Write Activate End
                        WRAP    = 5'h14,                // Write Command Precharge
                        WRSQ    = 5'h15,                // Write Command Sequential
                        WRNL    = 5'h16,                // Write Command Null
                        WTHR    = 5'h17,                // Write Thru (Activate)
                        RACT    = 5'h18,                // Read Activate
                        RVIR    = 5'h19,                // Read Activate Virtual
                        RNUL    = 5'h1a,                // Read Activate Null
                        REND    = 5'h1b,                // Read Activate End
                        RDAP    = 5'h1c,                // Read Command Precharge
                        RDSQ    = 5'h1d,                // Read Command Sequential
                        RDNL    = 5'h1e,                // Read Command Null
                        RTHR    = 5'h1f;                // Read Thru (Activate)

// ******************************* REFERENCE ***********************************

//                                      SDRAM ADDRESS FIELD
//                                      ===================
//                     15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0   B2 B1 B0
//              +======================================================+==========+
//      DIRECT  |      31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 | 14 13 12 |
//              +======================================================+==========+
//       ACT    | ROWS +F +E +D +C +B +A +9 +8 +7 +6 +5 +4 +3 +2 +1 +0 |  5  4  3 |
//              +------------------------------------------------------+----------+
//       COM    |      16 15 14  H 13 AP 12 11 10  9  8  7  6  L  L  L |  5  4  3 |
//              +======================================================+==========+
//
// 割り込みアクセス時、pAddr[31:16]→addr[15:0]、pAddr[14:12]→ba[2:0]にマッピング
// また、pAddr[8]→ras_n、pAddr[9]→cas_n、pAddr[10]→we_nにマッピング
// 通常アクセスのActivateで、iAddr[ROWS+15:ROWS]→addr[15:0]、iAddr[5:3]→ba[2:0]にマッピング
// 通常アクセスのR/WでiAddr[16:14]'1'[12:6]'000'→addr[15:0]にマッピング
//   ・DDR側でaddr[15:13]は使用しない
//   ・addr[12]は'1'にしてDDR3のBurst Chop機能を使わない
//   ・addr[10]は'1'にしてAuto Pre-charge機能を使う(ページ機能を実装するとここが変化)

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

        // Normal Master
        // 通常アクセスのRequest信号グループ(ハンドシェークを実施)
        input                   iReq;
        output                  iGnt;
        input                   iRxw;
        input   [31:0]          iAddr;

        // 割り込みアクセスのRequest信号グループ(ハンドシェークを実施)
        // Interrupt Master
        input                   pReq;
        output                  pGnt;
        input   [31:0]          pAddr;

        // sdcRdとsdcWrにR/Wコマンド発行タイミングを通知
        // Data Path Timing
        output                  wrPush;
        output                  rdPush;

        // PHYに接続するDDR信号、簡易版なのでCKEやODTは除かれている
        // SDRAM Interface
        output                  cs_n;
        output                  ras_n;
        output                  cas_n;
        output                  we_n;
        output  [15:0]          addr;
        output  [2:0]           ba;

        // 静的なパラメータ群、ステートマシンが停止している時点で取り込み
        // rdWL, rdRLはsdcWr, sdcRdへパラメータ伝達、一旦ラッチするためこのモジュールで管理
        // Register Interface
        input   [7:0]           reg_pACCW;      // BankごとのWriteアクセス占有間隔(min)
        input   [7:0]           reg_pACCR;      // BankごとのReadアクセス占有間隔(min)
        input   [7:0]           reg_pCOM;       // リフレッシュなど特殊コマンドの占有間隔(min)
        input   [4:0]           reg_pFAW;       // Activateが4つ存在してもよい間隔(max)
        input   [4:0]           reg_pRRD;       // Activateが2つ存在してもよい間隔(max)
        input   [4:0]           reg_dTWR;       // Write→Read遷移に必要な間隔(min)
        input   [4:0]           reg_dTRW;       // Read→Write遷移に必要な間隔(min)
        input   [4:0]           reg_dWL;        // 正確なWrite Latency
        input   [4:0]           reg_dRL;        // 正確なRead Latency
        output  [4:0]           rdWL;
        output  [4:0]           rdRL;

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

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

        // Parameter Latch
        // システムによっては不必要、その場合reg_*をそのまま使用
        reg     [7:0]           rpACCW, rpACCR, rpCOM;
        reg     [31:0]          rpFAW, rpRRD;
        reg     [4:0]           rdTWR, rdTRW;
        reg     [4:0]           rdWL, rdRL;

        // Status Control
        reg     [4:0]           state, stateD;  // 使用する状態は8つなので、3bitに圧縮可能
        reg                     setAct, setCom; // Activate, R/Wタイミング
        wire                    tiReq, tpReq;   // iReq, pReqをフィルタした信号(禁止期間マスク)
        reg                     iGnt, pGnt;
        reg                     wrPush, rdPush;
        reg                     wrPushD, rdPushD;
        reg     [31:0]          tmpAddr;        // DDRに接続するテンポラリアドレス
                                                // synopsys translate_off
        reg     [31:0]          stateName;      // synopsys translate_on     デバッグ用(ASCII)

        reg                     stateWait;      // 状態遷移指示信号evalOk生成用のカウンター
        wire                    stateWaitD;
        reg     [4:0]           stateCnt;       // 状態遷移指示信号wrOk, rdOk生成用のカウンター
        wire    [4:0]           stateCntD;

        // 通常アクセス時に使用する状態遷移指示信号
        wire                    waitInc, cntInc;
        reg                     evalOk, wrOk, rdOk;
        wire                    evalOkD, wrOkD, rdOkD;

        // Address Latch
        // iAddrを一旦ラッチ、R/Wコマンド発行時に使用
        reg     [31:0]          fifoAddr;

        // Normal Access Bank Count
        // 通常アクセス用のバンクごとの禁止区間生成用(ACCW, ACCRから生成)
        // FF間の論理段数削減のため、ラッチしたタイミング信号iDoneを用意
        reg     [7:0]           iRead;
        reg     [7:0]           iCnt[0:7], iCntD[0:7];
        reg     [7:0]           iDone;
        reg     [7:0]           iTerm, iTermD;
        reg                     iAccess;
        wire                    iAct;
        wire                    iAlloc          = iReq & iGnt;
        wire    [2:0]           iBank           = iAddr[5:3];

        // Special Access Count
        // 割り込みアクセス用の禁止区間生成用(COMから生成)
        // FF間の論理段数削減のため、ラッチしたタイミング信号pDoneを用意
        reg     [7:0]           pCnt;
        wire    [7:0]           pCntD;
        reg                     pDone;
        reg                     pAccess;
        wire                    pAlloc          = pReq & pGnt;

        // Four Active Window Control
        // 区間内のActivate数を数えるための変数
        reg                     actOver, actIn;
        wire    [2:0]           actFAW, actRRD;
        reg     [31:0]          actFIFO;

        // Output Signals
        // FF間の論理段数削減のため、状態をラッチしたタイミング信号(One hot)を用意
        reg                     statPrev, statIdleAp, statActIn, statWrRdAll, statWrAll;
        reg                     cs_n, ras_n, cas_n, we_n;
        reg     [15:0]          addr;
        reg     [2:0]           ba;
        wire    [15:0]          rowAddr, colAddr;

        // Utlity
        integer                 i;

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

// -----------------------------------------------------------------------------
// To Change Parameter
// 状態がIDLEならパラメータをラッチ、stateDを使用するのは前もって準備するため
// 引き算しているのは、ステートマシンの遷移時間や終了判定の時間を考慮してのもの
// spFuncは特殊カウンターactFIFOで使用するマスクを生成
// rvFuncは0以下になる可能性のある変数に対し、0以下は0になるよう補正
always @(posedge clk)
        if (stateD == IDLE) begin
                rpACCW          <= #1 reg_pACCW - 8'h02;
                rpACCR          <= #1 reg_pACCR - 8'h02;
                rpCOM           <= #1 reg_pCOM - 8'h04;
                rpFAW           <= #1 spFunc(reg_pFAW, 5'h04);
                rpRRD           <= #1 spFunc(reg_pRRD, 5'h04);
                rdTWR           <= #1 rvFunc(reg_dTWR, 5'h04);
                rdTRW           <= #1 rvFunc(reg_dTRW, 5'h04);
                rdWL            <= #1 reg_dWL - 5'h04;
                rdRL            <= #1 reg_dRL;
        end

// -----------------------------------------------------------------------------
// Reduced state machine
// メインのステートマシン
// 状態を表すstate、マスターへのgnt、コマンド発行タイミング、DDRへのアドレスを生成
always @(
        state or
        tiReq or iRxw or iAddr or iAccess or
        tpReq or pAccess or
        evalOk or wrOk or rdOk or
        fifoAddr or
        actOver
        ) begin

        // 最初にデフォルト値を設定、これを外れる条件のみcase()内で更新
        stateD          = state;
        iGnt            = 1'b0;
        pGnt            = 1'b0;
        setAct          = 1'b0;
        setCom          = 1'b0;
        wrPushD         = 1'b0;
        rdPushD         = 1'b0;
        tmpAddr         = fifoAddr;

        case (state)
                // IDLEは静止状態
                IDLE:   // idle: setup or ship any command
                begin                                   // synopsys translate_off
                        // 波形観測で状態名をASCII表示、合成時時は自動的にスキップ
                        stateName       = "IDLE";       // synopsys translate_on
                        casex ({actOver, tpReq, tiReq, iRxw, iAccess})
                                // WriteアクセスでActivateへ、iAccessは既にマスクされているため見ない
                                // このタイミングでOKならiGntをアサート
                                // Activateコマンドのタイミングを生成、iAddrをそのままaddr信号へ
                                5'b0010x: begin
                                        stateD  = WACT;
                                        iGnt    = 1'b1;
                                        setAct  = 1'b1;
                                        tmpAddr = iAddr;
                                end
                                // ReadアクセスでActivateへ、iAccessは既にマスクされているため見ない
                                // このタイミングでOKならiGntをアサート
                                // Activateコマンドのタイミングを生成、iAddrをそのままaddr信号へ
                                5'b0011x: begin
                                        stateD  = RACT;
                                        iGnt    = 1'b1;
                                        setAct  = 1'b1;
                                        tmpAddr = iAddr;
                                end
                                // 割り込みアクセス、上記に優先して遷移
                                // 通常アクセス(iAccess)に関するスケジュールが全て消えるまで待機
                                5'bx1xx0:
                                        stateD  = PREV;
                        endcase
                end

                // PREVは割り込みアクセスのコマンド発行の前段階(IDLEと同じ)
                // One hotを作るために定義
                PREV:   // idle: previous to ship direct command
                begin                                   // synopsys translate_off
                        stateName       = "PREV";       // synopsys translate_on
                                        stateD  = DIRC;
                                        setAct  = 1'b1;
                end

                // DIRCは任意コマンドの発行タイミング、ラッチアドレスをaddr信号へ
                // このタイミングでpGntをアサート
                DIRC:   // direct assert for any command
                begin                                   // synopsys translate_off
                        stateName       = "DIRC";       // synopsys translate_on
                                        stateD  = ABRT;
                                        pGnt    = 1'b1;
                end

                // ABRTは任意コマンドのACタイミング(COM)を満足するための待機状態
                ABRT:   // abort
                begin                                   // synopsys translate_off
                        stateName       = "ABRT";       // synopsys translate_on
                        // pReq & pGntで開始したカウントがCOMに未到達なら待機
                        if (!pAccess)
                                        stateD  = IDLE;
                end

                // WACTはActivateコマンドの発行タイミング、Writeの区別はWRAPに遷移するため
                WACT:   // activate command for write
                begin                                   // synopsys translate_off
                        stateName       = "WACT";       // synopsys translate_on
                        // evalOkを見て1サイクルNOPが挿入された後かをチェック
                        // Writeコマンドのタイミングを生成、ラッチアドレスをaddr信号へ
                        if (evalOk) begin
                                        stateD  = WRAP;
                                        setCom  = 1'b1;
                                        wrPushD = 1'b1;
                        end
                end

                // WRAPはWriteコマンドの発行タイミング、IDLEと同じく続くiReqをチェック
                WRAP:   // write command with precharge
                begin                                   // synopsys translate_off
                        stateName       = "WRAP";       // synopsys translate_on
                        casex ({actOver, evalOk, wrOk, tpReq, tiReq, iRxw})
                                // Writeアクセスが続き、actOver(RRD/FAW)とevalOkを満足すればWACTへ
                                // Write→WriteなのでwrOkは見ない
                                6'b01x010: begin
                                        stateD  = WACT;
                                        iGnt    = 1'b1;
                                        setAct  = 1'b1;
                                        tmpAddr = iAddr;
                                end
                                // Readアクセスに変わり、actOver(RRD/FAW)とwrOkを満足すればRACTへ
                                // wrOk成立時はevalOkも成立するので見ない
                                6'b0x1011: begin
                                        stateD  = RACT;
                                        iGnt    = 1'b1;
                                        setAct  = 1'b1;
                                        tmpAddr = iAddr;
                                end
                                // 割り込みアクセスがある場合は強制的にIDLEへ、IDLEでPREVに導かれる
                                // また、アクセスがなく全てのACタイミングが満たされればIDLEへ
                                6'bxxx1xx,
                                6'bxx100x:
                                        stateD  = IDLE;
                        endcase
                end

                // RACTはActivateコマンドの発行タイミング、Readの区別はRDAPに遷移するため
                RACT:   // activate command for read
                begin                                   // synopsys translate_off
                        stateName       = "RACT";       // synopsys translate_on
                        // evalOkを見て1サイクルNOPが挿入された後かをチェック
                        // Readコマンドのタイミングを生成、ラッチアドレスをaddr信号へ
                        if (evalOk) begin
                                        stateD  = RDAP;
                                        setCom  = 1'b1;
                                        rdPushD = 1'b1;
                        end
                end

                // RDAPはReadコマンドの発行タイミング、IDLEと同じく続くiReqをチェック
                RDAP:   // read command with precharge
                begin                                   // synopsys translate_off
                        stateName       = "RDAP";       // synopsys translate_on
                        casex ({actOver, evalOk, rdOk, tpReq, tiReq, iRxw})
                                6'b01x011: begin
                                // Readアクセスが続き、actOver(RRD/FAW)とevalOkを満足すればRACTへ
                                // Read→ReadなのでrdOkは見ない
                                        stateD  = RACT;
                                        iGnt    = 1'b1;
                                        setAct  = 1'b1;
                                        tmpAddr = iAddr;
                                end
                                // Writeアクセスに変わり、actOver(RRD/FAW)とrdOkを満足すればWACTへ
                                // rdOk成立時はevalOkも成立するので見ない
                                6'b0x1010: begin
                                        stateD  = WACT;
                                        iGnt    = 1'b1;
                                        setAct  = 1'b1;
                                        tmpAddr = iAddr;
                                end
                                // 割り込みアクセスがある場合は強制的にIDLEへ、IDLEでPREVに導かれる
                                // また、アクセスがなく全てのACタイミングが満たされればIDLEへ
                                6'bxxx1xx,
                                6'bxx100x:
                                        stateD  = IDLE;
                        endcase
                end
        endcase
end

// 状態とタイミング操作フラグをラッチ
always @(posedge clk or negedge reset_n)
        if (!reset_n) begin
                state           <= #1 IDLE;
                evalOk          <= #1 1'b0;
                stateWait       <= #1 1'b0;
                stateCnt        <= #1 5'h00;
                {wrOk, rdOk}    <= #1 2'b00;
        end
        else begin
                state           <= #1 stateD;
                evalOk          <= #1 evalOkD;
                stateWait       <= #1 stateWaitD;
                stateCnt        <= #1 stateCntD;
                {wrOk, rdOk}    <= #1 {wrOkD, rdOkD};
        end

// コマンド間にNOPを挿入するため、任意コマンドの発行でクリアし自動インクリメントするカウンター
assign stateWaitD       = (setAct | setCom)
                                ? 1'h0
                                : stateWait + waitInc;

// R/Wを跨ぐ間隔をチェックするため、R/Wコマンドの発行でクリアし自動インクリメントするカウンター
assign stateCntD        = setCom
                                ? 5'h00
                                : stateCnt + {4'd0, cntInc};

assign waitInc          = (state != IDLE) & (stateWait != 1'h1);
assign cntInc           = (state >= WACT) & (!wrOk | !rdOk);

assign evalOkD          = (stateWaitD == 1'h1);
assign wrOkD            = (stateCntD > rdTWR);
assign rdOkD            = (stateCntD > rdTRW);

// 通常アクセスのiReqは、バンクがBusyの場合マスク
assign tiReq            = iReq & !iAct;
assign tpReq            = pReq;

// -----------------------------------------------------------------------------
// Normal Access Bank Count
// バンクごとの通常アクセス期間(Busy)フラグiTermを生成
// iReq & iGntでカウントを1にセット、終了フラグiDoneでクリアする
always @(
        iCnt[0] or iCnt[1] or iCnt[2] or iCnt[3] or iCnt[4] or iCnt[5] or iCnt[6] or iCnt[7] or
        iDone or iTerm or iAlloc or iBank
        )
        for (i=0; i<8; i=i+1)
                if (iDone[i]) begin
                        iCntD[i]        = 8'h00;
                        iTermD[i]       = 1'b0;
                end
                else if (iAlloc & (i[2:0] == iBank)) begin
                        iCntD[i]        = 8'h01;
                        iTermD[i]       = 1'b1;
                end
                else begin
                        iCntD[i]        = iCnt[i] + {7'd0, iTerm[i]};
                        iTermD[i]       = iTerm[i];
                end

// iAccessはiTermをまとめたもの、ステートマシンで割り込みアクセス待ちに使う
always @(posedge clk or negedge reset_n)
        if (!reset_n)
                iAccess         <= #1 1'b0;
        else
                iAccess         <= #1 |iTermD;

// カウント判定値ACCはR/Wで異なるため、アクセスの種別をバンクごとに記録しておく
always @(posedge clk or negedge reset_n)
        if (!reset_n)
                iRead           <= #1 8'h00;
        else for (i=0; i<8; i=i+1)
                if (iAlloc & (i[2:0] == iBank))
                        iRead[i]        <= #1 iRxw;

// iCntだけでiTermを生成できるが、FF間の論理段数を減らすため補助的なフラグをFFで用意
always @(posedge clk or negedge reset_n)
        if (!reset_n) for (i=0; i<8; i=i+1) begin
                iCnt[i]         <= #1 8'h00;
                iDone[i]        <= #1 1'b0;
                iTerm[i]        <= #1 1'b0;
        end
        else for (i=0; i<8; i=i+1) begin
                iCnt[i]         <= #1 iCntD[i];
                iDone[i]        <= #1 (iCnt[i] == (iRead[i] ? rpACCR : rpACCW));
                iTerm[i]        <= #1 iTermD[i];
        end

// 通常アクセスの指定バンクからBusy信号を抽出、iReqにマスクする(iBankはiAddr[5:3]固定)
assign iAct             = iTerm[iBank];

// -----------------------------------------------------------------------------
// Special Access Count
// 割り込みアクセス期間(Busy)フラグpAccessを生成
// pReq & pGntでカウントを1にセット、終了フラグpDoneでクリアする
// その他は通常アクセスと同じ
always @(posedge clk or negedge reset_n)
        if (!reset_n) begin
                pCnt            <= #1 8'h00;
                pDone           <= #1 1'b0;
                pAccess         <= #1 1'b0;
        end
        else begin
                pCnt            <= #1 pCntD;
                pDone           <= #1 |pCnt & (pCnt == rpCOM);
                pAccess         <= #1 |pCntD;
        end

assign pCntD            = pDone
                                ? 8'h00
                                : pCnt + {7'd0, pAlloc | pAccess};

// -----------------------------------------------------------------------------
// Address FIFO
// 1回のマスターアクセスで2回のスレーブアクセスを行うため、2回目に使用するアドレスを保存
always @(posedge clk)
        if (iAlloc)
                fifoAddr        <= #1 iAddr;

// -----------------------------------------------------------------------------
// Flags
// sdcRd, sdcWrに出力するコマンドタイミング、ステートマシンのWACTとRACTでタネを生成しラッチ
always @(posedge clk or negedge reset_n)
        if (!reset_n) begin
                wrPush          <= #1 1'b0;
                rdPush          <= #1 1'b0;
        end
        else begin
                wrPush          <= #1 wrPushD;
                rdPush          <= #1 rdPushD;
        end

// -----------------------------------------------------------------------------
// Four Active Window Control
// 特殊カウンターactFIFOは32サイクル分のActivateコマンド発行の履歴を管理
// sumFuncはパラメータで必要領域だけをマスクし、そこの含まれる1の数を数える
always @(posedge clk or negedge reset_n)
        if (!reset_n) begin
                actOver         <= #1 1'b0;
                actIn           <= #1 1'b0;
                actFIFO         <= #1 32'h00000000;
        end
        else begin
                actOver         <= #1 (actFAW > 3'h4) | (actRRD > 3'h1);
                actIn           <= #1 (stateD == IDLE) | (stateD == WRAP) | (stateD == RDAP);
                actFIFO         <= #1 {actFIFO[30:0], setAct & actIn};
        end

assign actFAW           = sumFunc(actFIFO & rpFAW);
assign actRRD           = sumFunc(actFIFO & rpRRD);

// -----------------------------------------------------------------------------
// SDRAM One Hot State
// cs_n信号などは、ステートマシンの状態から作るのではなく、この便利信号から生成する
always @(posedge clk or negedge reset_n)
        if (!reset_n) begin
                statPrev        <= #1 1'b0;
                statIdleAp      <= #1 1'b1;
                statActIn       <= #1 1'b1;
                statWrRdAll     <= #1 1'b0;
                statWrAll       <= #1 1'b0;
        end
        else begin
                statPrev        <= #1 (stateD == PREV);
                statIdleAp      <= #1 (stateD == IDLE) | (stateD == WRAP) | (stateD == RDAP);
                statActIn       <= #1 (stateD == IDLE) | (stateD == WRAP) | (stateD == RDAP) |
                                      (stateD == PREV);
                statWrRdAll     <= #1 (stateD >= WACT);
                statWrAll       <= #1 (stateD >= WACT) & (stateD < RACT);
        end

// -----------------------------------------------------------------------------
// SDRAM Command Set
// DDRの制御信号は負論理、setActとsetComはステートマシンの組み合わせ変数なので論理段数が深いので注意
// それぞれの最初の式は割り込みアクセス用で、cs_n信号以外はpAddrの特定bitをアサインさせている
always @(posedge clk or negedge reset_n)
        if (!reset_n)
                cs_n            <= #1 1'b1;
        else
                cs_n            <= #1 ~(
                                        setAct & statPrev   |
                                        setAct & statIdleAp |
                                        setCom
                                        );

always @(posedge clk or negedge reset_n)
        if (!reset_n)
                ras_n           <= #1 1'b1;
        else
                ras_n           <= #1 ~(
                                        setAct & statPrev & ~pAddr[8] |
                                        setAct & statIdleAp
                                        );

always @(posedge clk or negedge reset_n)
        if (!reset_n)
                cas_n           <= #1 1'b1;
        else
                cas_n           <= #1 ~(
                                        setAct & statPrev & ~pAddr[9] |
                                        setCom & statWrRdAll
                                        );

always @(posedge clk or negedge reset_n)
        if (!reset_n)
                we_n            <= #1 1'b1;
        else
                we_n            <= #1 ~(
                                        setAct & statPrev & ~pAddr[10] |
                                        setCom & statWrAll
                                        );

// -----------------------------------------------------------------------------
// SDRAM Address Set
// DDRのバンク信号とアドレス信号
// それぞれの最初の式は割り込みアクセス用で、それぞれpAddr[14:12]とpAddr[31:16]をアサインさせている
always @(posedge clk or negedge reset_n)
        if (!reset_n)
                ba              <= #1 3'h0;
        else if (setAct & statActIn)
                ba              <= #1
                                        {3{statPrev}}   & pAddr[14:12] |
                                        {3{statIdleAp}} & tmpAddr[5:3];

always @(posedge clk or negedge reset_n)
        if (!reset_n)
                addr            <= #1 16'h0000;
        else if (setAct & statActIn | setCom)
                addr            <= #1
                                        {16{setAct & statPrev}}   & pAddr[31:16] |
                                        {16{setAct & statIdleAp}} & rowAddr      |
                                        {16{setCom}}              & colAddr;

// 通常アクセスのRowアドレスはiAddrから生成、パラメータ文で定義したROWSをLSBに切り出し
assign rowAddr          = addrRowFunc(tmpAddr, ROWS);
// 通常アクセスのColumnアドレスはラッチアドレスから生成
assign colAddr          = addrColFunc(tmpAddr);

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

// 入力アドレスからRowアドレスへのマッピング
// rsはパラメータ文で定義した値なので簡単に表現できるが、レジスタ化を考慮した記述にする
function [15:0] addrRowFunc;
        input   [31:0]          addr;
        input   [4:0]           rs;

        case (rs)
                5'h08:  addrRowFunc     = addr[23:8];
                5'h09:  addrRowFunc     = addr[24:9];
                5'h0a:  addrRowFunc     = addr[25:10];
                5'h0b:  addrRowFunc     = addr[26:11];
                5'h0c:  addrRowFunc     = addr[27:12];
                5'h0d:  addrRowFunc     = addr[28:13];
                5'h0e:  addrRowFunc     = addr[29:14];
                5'h0f:  addrRowFunc     = addr[30:15];
                default:
                        addrRowFunc     = addr[31:16];
        endcase
endfunction

// 入力アドレスからColumnアドレスへのマッピング
// DDRのワード長が変われば、最初のif文の3の数字が変わる(ここでは8bitなので8バーストを表現できる3)
function [15:0] addrColFunc;
        input   [31:0]          addr;
        integer                 i;

        for (i=0; i<16; i=i+1)
                if (i < 3)
                        addrColFunc[i]  = 1'b0;
                else if (i < 10)
                        addrColFunc[i]  = addr[i+3];
                else if (i < 11)                        // ap
                        addrColFunc[i]  = 1'b1;
                else if (i < 12)
                        addrColFunc[i]  = addr[13];
                else if (i < 13)                        // bc
                        addrColFunc[i]  = 1'b1;
                else
                        addrColFunc[i]  = addr[i+1];
endfunction

// 特殊カウンター用のマスク生成
function [31:0] spFunc;
        input   [4:0]           sp;
        input   [4:0]           bias;
        reg     [5:0]           tmp;
        reg     [4:0]           sft;
        integer                 i;

        begin
                // 最初に補正値を引いておく(負であれば0)
                tmp             = {1'd0, sp} - {1'd0, bias};
                sft             = (~|sp | tmp[5]) ? 5'h00 : tmp[4:0];

                // 補正値を境界に、LSB方向に1、MSB方向に0(LSBは必ず1)
                for (i=0; i<32; i=i+1)
                        spFunc[i]       = (sft < i[4:0]) ? 1'b0 : 1'b1;
        end
endfunction

// 補正値を引き、0以下は0にするだけ
function [4:0] rvFunc;
        input   [4:0]           val;
        input   [4:0]           bias;
        reg     [5:0]           tmp;

        begin
                tmp             = {1'd0, val} - {1'd0, bias};

                rvFunc          = tmp[5] ? 5'h00 : tmp[4:0];
        end
endfunction

// 特殊カウンター内の1の個数を数える
// 4つ以上のActivateは入らない制御なので、4まで数えればよい
function [2:0] sumFunc;
        input   [31:0]          act;
        reg     [5:0]           sum;
        integer                 i;

        begin
                sum             = 6'h00;

                for (i=0; i<32; i=i+1)
                        sum             = sum + {5'd0, act[i]};

                sumFunc         = sum[2:0];             // Clip since sum <= 4
        end
endfunction

endmodule

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

回路デザイン > 設計例 [DDR制御(論理)] > コーディング1    次のページ(コーディング2)   このページのTOP ▲