/* **************************** 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
// *****************************************************************************