/* **************************** 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 ****************************
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
// [16bit DDR] ===================
// 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 | 6 5 4 |
// +------------------------------------------------------+----------+
// COM | 17 16 15 H 14 AP 13 12 11 10 9 8 7 L L L | 6 5 4 |
// +======================================================+==========+
//
// pAddr[8]→ras_n、pAddr[9]→cas_n、pAddr[10]→we_nに加えてpAddr[0]→cs_nをマッピング
// 通常アクセスのActivateで、iAddr[ROWS+15:ROWS]→addr[15:0]、iAddr[6:4]→ba[2:0]にマッピング
// 通常アクセスのR/WでiAddr[17:15]'1'[13:7]'000'→addr[15:0]にマッピング
// ・DDR側でaddr[15:14]は使用しない
// *************************** I/O DECLARATIONS ********************************
// Normal Master
input iReq;
output iGnt;
input iRxw;
input [31:0] iAddr;
// Interrupt Master
input pReq;
output pGnt;
input [31:0] pAddr;
// Data Path Timing
output wrPush;
output rdPush;
// SDRAM Interface
output cs_n;
output ras_n;
output cas_n;
output we_n;
output [15:0] addr;
output [2:0] ba;
// Register Interface
input [7:0] reg_pACCW;
input [7:0] reg_pACCR;
input [7:0] reg_pCOM;
input [4:0] reg_pFAW;
input [4:0] reg_pRRD;
input [4:0] reg_dTWR;
input [4:0] reg_dTRW;
input [4:0] reg_dWL;
input [4:0] reg_dRL;
output [4:0] rdWL;
output [4:0] rdRL;
// Utility
input clk;
input reset_n;
// ************************** LOCAL DECLARATIONS *******************************
// Parameter Latch
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;
reg setAct, setCom;
wire tiReq, tpReq;
reg iGnt, pGnt;
reg wrPush, rdPush;
reg wrPushD, rdPushD;
reg [31:0] tmpAddr;
// synopsys translate_off
reg [31:0] stateName; // synopsys translate_on
reg stateWait;
wire stateWaitD;
reg [4:0] stateCnt;
wire [4:0] stateCntD;
wire waitInc, cntInc;
reg evalOk, wrOk, rdOk;
wire evalOkD, wrOkD, rdOkD;
// Address Latch
reg [31:0] fifoAddr;
// Normal Access Bank Count
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;
// BankアドレスをDDR 16bit版に変更
wire [2:0] iBank = iAddr[6:4];
// Special Access Count
reg [7:0] pCnt;
wire [7:0] pCntD;
reg pDone;
reg pAccess;
wire pAlloc = pReq & pGnt;
// Four Active Window Control
reg actOver, actIn;
wire [2:0] actFAW, actRRD;
reg [31:0] actFIFO;
// Output Signals
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
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'h03;
rdRL <= #1 reg_dRL;
end
// -----------------------------------------------------------------------------
// Reduced state machine
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
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: setup or ship any command
begin // synopsys translate_off
stateName = "IDLE"; // synopsys translate_on
casex ({actOver, tpReq, tiReq, iRxw, iAccess})
5'b0010x: begin
stateD = WACT;
iGnt = 1'b1;
setAct = 1'b1;
tmpAddr = iAddr;
end
5'b0011x: begin
stateD = RACT;
iGnt = 1'b1;
setAct = 1'b1;
tmpAddr = iAddr;
end
5'bx1xx0:
stateD = PREV;
endcase
end
PREV: // idle: previous to ship direct command
begin // synopsys translate_off
stateName = "PREV"; // synopsys translate_on
stateD = DIRC;
setAct = 1'b1;
end
DIRC: // direct assert for any command
begin // synopsys translate_off
stateName = "DIRC"; // synopsys translate_on
stateD = ABRT;
pGnt = 1'b1;
end
ABRT: // abort
begin // synopsys translate_off
stateName = "ABRT"; // synopsys translate_on
if (!pAccess)
stateD = IDLE;
end
WACT: // activate command for write
begin // synopsys translate_off
stateName = "WACT"; // synopsys translate_on
if (evalOk) begin
stateD = WRAP;
setCom = 1'b1;
wrPushD = 1'b1;
end
end
WRAP: // write command with precharge
begin // synopsys translate_off
stateName = "WRAP"; // synopsys translate_on
casex ({actOver, evalOk, wrOk, tpReq, tiReq, iRxw})
6'b01x010: begin
stateD = WACT;
iGnt = 1'b1;
setAct = 1'b1;
tmpAddr = iAddr;
end
6'b0x1011: begin
stateD = RACT;
iGnt = 1'b1;
setAct = 1'b1;
tmpAddr = iAddr;
end
6'bxxx1xx,
6'bxx100x:
stateD = IDLE;
endcase
end
RACT: // activate command for read
begin // synopsys translate_off
stateName = "RACT"; // synopsys translate_on
if (evalOk) begin
stateD = RDAP;
setCom = 1'b1;
rdPushD = 1'b1;
end
end
RDAP: // read command with precharge
begin // synopsys translate_off
stateName = "RDAP"; // synopsys translate_on
casex ({actOver, evalOk, rdOk, tpReq, tiReq, iRxw})
6'b01x011: begin
stateD = RACT;
iGnt = 1'b1;
setAct = 1'b1;
tmpAddr = iAddr;
end
6'b0x1010: begin
stateD = WACT;
iGnt = 1'b1;
setAct = 1'b1;
tmpAddr = iAddr;
end
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
assign stateWaitD = (setAct | setCom)
? 1'h0
: stateWait + waitInc;
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);
assign tiReq = iReq & !iAct;
assign tpReq = pReq;
// -----------------------------------------------------------------------------
// Normal Access Bank Count
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
always @(posedge clk or negedge reset_n)
if (!reset_n)
iAccess <= #1 1'b0;
else
iAccess <= #1 |iTermD;
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;
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
assign iAct = iTerm[iBank];
// -----------------------------------------------------------------------------
// Special Access Count
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
always @(posedge clk)
if (iAlloc)
fifoAddr <= #1 iAddr;
// -----------------------------------------------------------------------------
// Flags
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
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
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
// 割り込みアクセス用の最初の式で、cs_n信号にpAddr[0]をアサイン
always @(posedge clk or negedge reset_n)
if (!reset_n)
cs_n <= #1 1'b1;
else
cs_n <= #1 ~(
setAct & statPrev & ~pAddr[0] |
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 16bit版に対応したバンク信号とアドレス信号
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[6:4];
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;
assign rowAddr = addrRowFunc(tmpAddr, ROWS);
assign colAddr = addrColFunc(tmpAddr);
// ************************** FUNCTIONS and TASKS ******************************
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 16bit版に対応するためのファンクションに変更
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+4];
else if (i < 11) // ap
addrColFunc[i] = 1'b1;
else if (i < 12)
addrColFunc[i] = addr[14];
else if (i < 13) // bc
addrColFunc[i] = 1'b1;
else
addrColFunc[i] = addr[i+2];
endfunction
function [31:0] spFunc;
input [4:0] sp;
input [4:0] bias;
reg [5:0] tmp;
reg [4:0] sft;
integer i;
begin
tmp = {1'd0, sp} - {1'd0, bias};
sft = (~|sp | tmp[5]) ? 5'h00 : tmp[4:0];
for (i=0; i<32; i=i+1)
spFunc[i] = (sft < i[4:0]) ? 1'b0 : 1'b1;
end
endfunction
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
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
// *****************************************************************************