📄 ddr_ctrl.v
字号:
case (cstate)
c_idle: begin
if (!rd_wr_req_during_ref_req)
if (!sys_adsn_r && latch_ref_req)
rd_wr_req_during_ref_req <= 1'b1;
else
rd_wr_req_during_ref_req <= 1'b0;
end
// After completing write (c_tDAL)
// Durinf c_tDAL, system can make a request and
// refresh can be pending.
c_tRFC,
c_tDAL,
c_AR: begin
if (!sys_adsn_r)
rd_wr_req_during_ref_req <= sys_init_done;
end
default: begin
rd_wr_req_during_ref_req <= 1'b0;
end
endcase
end
end
//=======================================================================
// CMD_FSM state machine
//=======================================================================
always @(posedge clk or negedge reset_n) begin
if (reset_n == 1'b0) begin
cstate <= c_idle;
wren <= 1'b0;
end else begin
case (cstate)
c_idle: // wait until refresh request or addr strobe asserted
if (latch_ref_req && sys_init_done)
cstate <= c_AR;
else if ((!sys_adsn_r && sys_init_done) || rd_wr_req_during_ref_req)
cstate <= c_ACTIVE;
c_ACTIVE: // assert row/bank addr
if (NUM_CLK_tRCD == 0)
cstate <= (sys_r_wn_r) ? c_READA : c_WRITEA;
else
cstate <= c_tRCD;
c_tRCD: // wait until tRCD satisfied
if (`endOf_tRCD)
cstate <= (sys_r_wn_r) ? c_READA : c_WRITEA;
c_READA: // assert col/bank addr for read with auto-precharge
cstate <= c_cl;
c_cl: // CASn latency
if (`endOf_Cas_Latency) cstate <= c_rdata;
c_rdata: // read cycle data phase
if (`endOf_Read_Burst) cstate <= c_idle;
c_WRITEA: begin // assert col/bank addr for write with auto-precharge
cstate <= c_wdata;
wren <= 1'b1;
end
c_wdata: begin // write cycle data phase
if (`endOf_Write_Burst) begin
cstate <= c_tDAL;
wren <= 1'b0;
end
end
c_tDAL: // wait until (tWR + tRP) satisfied before issuing next
// SDRAM ACTIVE command
if (`endOf_tDAL) cstate <= c_idle;
c_AR: // auto-refresh
cstate <= (NUM_CLK_tRFC == 0) ? c_idle : c_tRFC;
c_tRFC: // wait until tRFC satisfied
if (`endOf_tRFC) cstate <= c_idle;
default: begin
cstate <= c_idle;
wren <= 1'b0;
end
endcase
end
end
//=======================================================================
// Refresh request, generation using LFSR counters
// for better frequency and resource utilisation
// For more information please refer to
// http://www.fpgacpu.org/usenet/lfsrs.html
// Use the lfsr.exe, if any changes are required.
//lfsr 11 1500
//lfsr 11-bits 1500-cycle=477
//lfsr 11-bits 1500-cycle: d0=xnor(q10,q8, /*477*/and(q10,~q9,~q8,~q7,q6,q5,q4,~q3,q2,q1,q0));
//lfsr 11 750
//lfsr 11-bits 750-cycle=605
//lfsr 11-bits 750-cycle: d0=xnor(q10,q8, /*605*/and(q10,q9,~q8,~q7,~q6,~q5,~q4,~q3,q2,~q1,q0));
//lfsr 11 2000
//lfsr 11-bits 2000-cycle=300
//lfsr 11-bits 2000-cycle: d0=xnor(q10,q8, /*300*/and(~q10,q9,q8,~q7,~q6,~q5,~q4,~q3,~q2,~q1,~q0));
//lfsr 11 1000
//lfsr 11-bits 1000-cycle=350
//lfsr 11-bits 1000-cycle: d0=xnor(q10,q8, /*350*/and(~q10,q9,q8,~q7,q6,~q5,q4,~q3,~q2,~q1,~q0));
//=======================================================================
always @(posedge clk or negedge reset_n) begin
if (reset_n == 1'b0) begin
q <= 0;
ref_req <= 1'b0;
end else begin
q[0] <= ~(q[10]^q[8]^ref_req_c);
q[10:1] <= q[9:0];
ref_req <= ref_req_c;
end
end
always @ (q) begin
if (REF_INTERVAL == REF_INT_128MBIT_100MHZ)
/*477*/ref_req_c = q[10]&~q[9]&~q[8]&~q[7]&q[6]&q[5]&q[4]&~q[3]&q[2]&q[1]&q[0];
if (REF_INTERVAL == REF_INT_NON128MBIT_100MHZ)
/*605*/ref_req_c = q[10]&q[9]&~q[8]&~q[7]&~q[6]&~q[5]&~q[4]&~q[3]&q[2]&~q[1]&q[0];
if (REF_INTERVAL == REF_INT_128MBIT_133MHZ)
/*300*/ref_req_c = ~q[10]&q[9]&q[8]&~q[7]&~q[6]&~q[5]&~q[4]&~q[3]&~q[2]&~q[1]&~q[0];
if (REF_INTERVAL == REF_INT_NON128MBIT_133MHZ)
/*350*/ref_req_c = ~q[10]&q[9]&q[8]&~q[7]&q[6]&~q[5]&q[4]&~q[3]&~q[2]&~q[1]&~q[0];
end
always @(posedge clk or negedge reset_n) begin
if (reset_n == 1'b0) begin
ref_ack <= 0;
latch_ref_req <= 1'b0;
end else begin
if (ref_req)
latch_ref_req <= 1'b1;
else if (ref_ack)
latch_ref_req <= 1'b0;
case (cstate)
c_idle:
ref_ack <= sys_init_done && latch_ref_req;
default:
ref_ack <= 1'b0;
endcase
end
end
//=======================================================================
// Clock Counter
//=======================================================================
always @(posedge clk or negedge reset_n) begin
if (reset_n == 1'b0) begin
cs_clkcnt <= 4'b0;
end else begin
if (cs_syncResetClkCNT)
cs_clkcnt <= 4'b0;
else
cs_clkcnt <= cs_clkcnt + 1'b1;
end
end
always @(posedge clk or negedge reset_n) begin
if (reset_n == 1'b0) begin
i_clkcnt <= 4'b0;
end else begin
if (i_syncResetClkCNT)
i_clkcnt <= 4'b0;
else
i_clkcnt <= i_clkcnt + 1'b1;
end
end
//=======================================================================
// istate syncResetClkCNT generation
//=======================================================================
always @(istate or i_clkcnt) begin
case (istate)
i_PRE:
i_syncResetClkCNT = (NUM_CLK_tRP == 0) ? 1 : 0;
i_AR1,
i_AR2:
i_syncResetClkCNT = (NUM_CLK_tRFC == 0) ? 1 : 0;
i_tRP:
i_syncResetClkCNT = (`endOf_tRP_i) ? 1 : 0;
i_tMRD:
i_syncResetClkCNT = (`endOf_tMRD_i) ? 1 : 0;
i_tRFC1,
i_tRFC2:
i_syncResetClkCNT = (`endOf_tRFC_i) ? 1 : 0;
default:
i_syncResetClkCNT = 1;
endcase
end
//=======================================================================
// cstate syncResetClkCNT generation
//=======================================================================
always @(cstate or cs_clkcnt) begin
case (cstate)
c_idle:
cs_syncResetClkCNT = 1;
c_ACTIVE:
cs_syncResetClkCNT = (NUM_CLK_tRCD == 0) ? 1 : 0;
c_tRCD:
cs_syncResetClkCNT = (`endOf_tRCD) ? 1 : 0;
c_tRFC:
cs_syncResetClkCNT = (`endOf_tRFC) ? 1 : 0;
c_cl:
cs_syncResetClkCNT = (`endOf_Cas_Latency) ? 1 : 0;
c_rdata:
cs_syncResetClkCNT = (cs_clkcnt == NUM_CLK_READ) ? 1 : 0;
c_wdata:
cs_syncResetClkCNT = (`endOf_Write_Burst) ? 1 : 0;
c_tDAL:
cs_syncResetClkCNT = (`endOf_tDAL) ? 1 : 0;
default:
cs_syncResetClkCNT = 1;
endcase // case(cstate)
end
endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -