上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人
5.3 SDRAM控制器源代码分析
5.3.1 SDRAM控制器源代码列表
控制器源代码文件列表如下:
5.3.2 SDRAM初始化和WISHBONE从设备接口
sdr_wb_if.v完成SDRAM初始化和WISHBONE从设备接口,该设计的状态机方框图如图5-9所示。
图5-9 SDRAM初始化状态机
其设计源代码如下:
//chenxi01@ict.ac.cn `include "timescale.v" module sdr_wb_if( clk_i, rst_i, cyc_i, stb_i, dat_i, dat_o, adr_i, we_i, ack_o, sel_i, istate, cstate, sys_addr, sdr_dq, sdr_dqm); `include "sdr_defines.v" ……//此处忽略输入输出信号 wire sys_init_done; //表示SDRAM初始化结束 reg sys_ref_req; reg [3:0] istate; // 初始化状态机状态 reg [3:0] cstate; //命令状态机状态 reg [3:0] clkCNT; reg syncResetClkCNT; // reset clkCNT to 0 reg drive_data; reg [31:0] sdr_dq_out; assign sdr_dq= drive_data?sdr_dq_out:32'bzzzz_zzzz_zzzz_zzzz_zzzz_zzzz_zzzz_zzzz; //--------------------------------------------------------------------- // local definitions `define endOf_tRP clkCNT == NUM_CLK_tRP `define endOf_tRFC clkCNT == NUM_CLK_tRFC `define endOf_tMRD clkCNT == NUM_CLK_tMRD `define endOf_tRCD clkCNT == NUM_CLK_tRCD `define endOf_Cas_Latency clkCNT == NUM_CLK_CL `define endOf_Read_Burst clkCNT == NUM_CLK_READ -1 `define endOf_Write_Burst clkCNT == NUM_CLK_WRITE `define endOf_tDAL clkCNT == NUM_CLK_WAIT //初始化状态机 reg sys_delay_200us; reg [14:0] sys_delay_cnt; always @(posedge clk_i or posedge rst_i) begin if(rst_i) begin sys_delay_200us<=0; sys_delay_cnt<=0; end else begin if(sys_delay_cnt<15'h7fff) sys_delay_cnt<=sys_delay_cnt+1; else sys_delay_200us<=1; end end reg second_set; always @(posedge clk_i or posedge rst_i) if (rst_i) begin istate <= #tDLY i_NOP; second_set<=0; end else case (istate) i_NOP: // 等待200us if (sys_delay_200us) istate <= #tDLY i_PRE; i_PRE: //预充电,即PPrecharge all istate <= #tDLY (NUM_CLK_tRP == 0) ? i_AR1 : i_tRP; i_tRP: //等待tRP if (`endOf_tRP) istate <= #tDLY i_AR1; i_AR1: // Auto Referesh istate <= #tDLY (NUM_CLK_tRFC == 0) ? i_AR2 : i_tRFC1; i_tRFC1: // 等待tRFC if (`endOf_tRFC) istate <= #tDLY i_AR2; i_AR2: // Auto Referesh istate <= #tDLY (NUM_CLK_tRFC == 0) ? i_MRS : i_tRFC2; i_tRFC2: //等待tRFC if (`endOf_tRFC) istate <= #tDLY i_MRS; i_MRS: // Load Mode Register istate <= #tDLY (NUM_CLK_tMRD == 0) ? i_ready : i_tMRD; i_tMRD: //等待tMRD if (`endOf_tMRD) begin if(second_set) istate <= #tDLY i_ready; else begin second_set<=1; istate <= #tDLY i_NOP; end end i_ready: // stay at this state for normal operation istate <= #tDLY i_ready; default: istate <= #tDLY i_NOP; endcase //命令状态机State Machine assign sys_init_done=istate==i_ready; reg we_i_reg; always @(posedge clk_i or posedge rst_i) if (rst_i) begin cstate <= #tDLY c_idle; sdr_dq_out<=#tDLY 0; sdr_dqm<=#tDLY 4'b0; ack_o<=#tDLY 1'b0; drive_data<=#tDLY 1'b0; sys_addr<=#tDLY 1'b0; dat_o<=#tDLY 1'b0; we_i_reg<=#tDLY 1'b0; sdr_dqm<=#tDLY 4'b1111; end else case (cstate) c_idle: begin // wait until refresh request or addr strobe asserted if (sys_ref_req && sys_init_done) cstate <= #tDLY c_AR; else if (cyc_i&stb_i&sys_init_done&(!ack_o)) begin cstate <= #tDLY c_ACTIVE; end sys_addr<=#tDLY adr_i[23:2]; we_i_reg<=#tDLY we_i; if (cyc_i&stb_i&sys_init_done&we_i&(!ack_o)) begin ack_o<=#tDLY 1'b1; sdr_dq_out<=#tDLY dat_i; sdr_dqm<=#tDLY ~sel_i; end else begin ack_o<=#tDLY 1'b0; if(sys_init_done) sdr_dqm<=#tDLY 4'b0; else sdr_dqm<=#tDLY 4'b1111; end drive_data<=#tDLY 1'b0; end c_ACTIVE: begin // assert row/Bank addr ack_o<=1'b0; drive_data<=#tDLY we_i_reg; if (NUM_CLK_tRCD == 0) cstate <= #tDLY (we_i_reg) ? c_WRITEA:c_READA; else cstate <= #tDLY c_tRCD; end c_tRCD: // wait until tRCD satisfied if (`endOf_tRCD) cstate <= #tDLY (we_i_reg) ? c_WRITEA:c_READA; c_READA: // assert col/Bank addr for read with auto-PPrecharge cstate <= #tDLY c_cl; c_cl: // CASn latency if (`endOf_Cas_Latency) cstate <= #tDLY c_rdata; c_rdata: begin // read cycle data phase ack_o<=1'b1; dat_o<=sdr_dq; if (`endOf_Read_Burst) cstate <= #tDLY c_idle; end c_WRITEA: begin // assert col/Bank addr for write with auto-PPrecharge cstate <= #tDLY c_wdata; end c_wdata: // write cycle data phase if (`endOf_Write_Burst) cstate <= #tDLY c_tDAL; c_tDAL: // wait until (tWR + tRP) satisfied before issuing next // SDRAM ACTIVE command if (`endOf_tDAL) begin cstate <= #tDLY c_idle; drive_data<=1'b0; end c_AR: // auto-refresh cstate <= #tDLY (NUM_CLK_tRFC == 0) ? c_idle : c_tRFC; c_tRFC: // wait until tRFC satisfied if (`endOf_tRFC) cstate <= #tDLY c_idle; default: cstate <= #tDLY c_idle; endcase // sys_ref_req generation parameter REFRESH_CNT_MAX=10'd600; reg [9:0] refresh_cnt; always @(posedge clk_i or posedge rst_i) begin if (rst_i) begin refresh_cnt <= #tDLY 0; end else begin if(sys_init_done) begin if(refresh_cnt<=REFRESH_CNT_MAX) refresh_cnt<=#tDLY refresh_cnt+1; else refresh_cnt<=#tDLY 0; end else refresh_cnt <= #tDLY 0; end end always @(posedge clk_i or posedge rst_i) begin if (rst_i) begin sys_ref_req <= #tDLY 0; end else begin if(refresh_cnt==REFRESH_CNT_MAX) begin sys_ref_req <= #tDLY 1; end else if (cstate == c_AR) sys_ref_req <= #tDLY 0; end end // Clock Counter always @(posedge clk_i) if (syncResetClkCNT) clkCNT <= #tDLY 0; else clkCNT <= #tDLY clkCNT + 1; // syncResetClkCNT generation always @(istate or cstate or clkCNT) case (istate) i_PRE: syncResetClkCNT <= #tDLY (NUM_CLK_tRP == 0) ? 1 : 0; i_AR1, i_AR2: syncResetClkCNT <= #tDLY (NUM_CLK_tRFC == 0) ? 1 : 0; i_NOP: syncResetClkCNT <= #tDLY 1; i_tRP: syncResetClkCNT <= #tDLY (`endOf_tRP) ? 1 : 0; i_tMRD: syncResetClkCNT <= #tDLY (`endOf_tMRD) ? 1 : 0; i_tRFC1, i_tRFC2: syncResetClkCNT <= #tDLY (`endOf_tRFC) ? 1 : 0; i_ready: case (cstate) c_ACTIVE: syncResetClkCNT <= #tDLY (NUM_CLK_tRCD == 0) ? 1 : 0; c_idle: syncResetClkCNT <= #tDLY 1; c_tRCD: syncResetClkCNT <= #tDLY (`endOf_tRCD) ? 1 : 0; c_tRFC: syncResetClkCNT <= #tDLY (`endOf_tRFC) ? 1 : 0; c_cl: syncResetClkCNT <= #tDLY (`endOf_Cas_Latency) ? 1 : 0; c_rdata:syncResetClkCNT <= #tDLY (clkCNT == NUM_CLK_READ) ? 1 : 0; c_wdata: syncResetClkCNT <= #tDLY (`endOf_Write_Burst) ? 1 : 0; default: syncResetClkCNT <= #tDLY 0; endcase default: syncResetClkCNT <= #tDLY 0; endcase endmodule
5.3.3 SDRAM操作主状态机
sdr_sig.v实现了SDRAM操作主状态机,其状态转移如图5-10所示。
图5-10 SDRAM控制器主状态机
其设计源代码如下:
//chenxi01@ict.ac.cn `include "timescale.v" `define sdr_COMMAND {sdr_csn, sdr_rasn, sdr_casn, sdr_wen} module sdr_sig(clk_i, rst_i, sys_addr, istate, cstate, sdr_cke, sdr_csn, sdr_rasn, sdr_casn, sdr_wen, sdr_ba, sdr_addr); `include "sdr_defines.v" ……//忽略输入输出信号 // SDR SDRAM Control Singals always @(posedge clk_i or posedge rst_i) if (rst_i) begin `sdr_COMMAND <= #tDLY INHIBIT; sdr_cke <= #tDLY 0; sdr_ba<= #tDLY 2'b11;sdr_addr<= #tDLY 12'b1111_1111_1111; end else case (istate) i_tRP, i_tRFC1, i_tRFC2, i_tMRD, i_NOP: begin `sdr_COMMAND <= #tDLY NOP; sdr_cke <= #tDLY 1; sdr_ba <= #tDLY 2'b11; sdr_addr <= #tDLY 12'b1111_1111_1111; end i_PRE: begin `sdr_COMMAND <= #tDLY PPRECHARGE; sdr_cke <= #tDLY 1; sdr_ba <= #tDLY 2'b00; sdr_addr <= #tDLY 12'b1111_1111_1111; end i_AR1, i_AR2: begin `sdr_COMMAND <= #tDLY AUTO_REFRESH; sdr_cke <= #tDLY 1; sdr_ba <= #tDLY 2'b11; sdr_addr <= #tDLY 12'b1111_1111_1111; end i_MRS: begin `sdr_COMMAND <= #tDLY LOAD_MODE_REGISTER; sdr_cke <= #tDLY 1; sdr_ba <= #tDLY 2'b00; sdr_addr <= #tDLY {2'b00, MR_Write_Burst_Mode, MR_Operation_Mode,MR_CAS_Latency, MR_Burst_Type, MR_Burst_Length}; end i_ready: case (cstate) c_idle, c_tRCD, c_tRFC, c_cl, c_rdata, c_wdata: begin `sdr_COMMAND <= #tDLY NOP; sdr_cke <= #tDLY 1; sdr_ba <= #tDLY 2'b11; sdr_addr <= #tDLY 12'b1111_1111_1111; end c_ACTIVE: begin `sdr_COMMAND <= #tDLY ACTIVE; sdr_cke <= #tDLY 1; sdr_ba <= #tDLY sys_addr[BA_MSB:BA_LSB];//Bank sdr_addr <= #tDLY sys_addr[RA_MSB:RA_LSB];//row end c_READA: begin `sdr_COMMAND <= #tDLY READ; sdr_cke <= #tDLY 1; sdr_ba <= #tDLY sys_addr[BA_MSB:BA_LSB];//Bank sdr_addr <= #tDLY { 4'b0100, //enable auto PPrecharge sys_addr[CA_MSB:CA_LSB]//column }; end c_WRITEA: begin `sdr_COMMAND <= #tDLY WRITE; sdr_cke <= #tDLY 1; sdr_ba <= #tDLY sys_addr[BA_MSB:BA_LSB];//Bank sdr_addr <= #tDLY { 4'b0100, //enable auto PPrecharge,A10 sys_addr[CA_MSB:CA_LSB]//column }; end c_AR: begin `sdr_COMMAND <= #tDLY AUTO_REFRESH; sdr_cke <= #tDLY 1; sdr_ba <= #tDLY 2'b11; sdr_addr <= #tDLY 12'b1111_1111_1111; end default: begin `sdr_COMMAND <= #tDLY NOP; sdr_cke <= #tDLY 1; sdr_ba <= #tDLY 2'b11; sdr_addr <= #tDLY 12'b1111_1111_1111; end endcase default: begin `sdr_COMMAND <= #tDLY NOP; sdr_cke <= #tDLY 1; sdr_ba <= #tDLY 2'b11; sdr_addr <= #tDLY 12'b1111_1111_1111; end endcase endmodule
5.3.4 SDRAM控制器顶层模块
sdr_sdramc_top定义了SDRAM控制器顶层模块,将SDRAM控制器的各个模块连接在一起。其源代码如下所示。
`include "timescale.v" //`define SIMULATION module sdr_sdramc_top(clk_i,rst_i,we_i,data_i,data_o,addr_i,cyc_i,stb_i,ack_o,rty_o,err_o, sel_i,sdr_addr,sdr_ba,sdr_wen,sdr_csn,sdr_cke,sdr_rasn,sdr_casn,sdr_dq,sdr_dqm); `include "sdr_defines.v" ……//忽略输入输出信号 `ifdef SIMULATION assign ack_o=cyc_i&stb_i; assign rty_o=0; assign err_o=0; reg [31:0]data_o; always @(posedge clk_i or posedge rst_i) if(rst_i) begin data_o=0; end else begin if(we_i& ack_o & data_i[23:0]!=addr_i) $stop; if((!we_i)& ack_o ) begin data_o[23:0]=addr_i; end end `else wire [21:0] sys_addr; wire [3:0] istate; wire [3:0] cstate; sdr_wb_if sdr_wb_if(.clk_i(clk_i),.rst_i(rst_i),.cyc_i(cyc_i),.stb_i(stb_i),.dat_i(data_i), .dat_o(data_o),.adr_i(addr_i),.we_i(we_i),.ack_o(ack_o),.sel_i(sel_i),.istate(istate ),.cstate(cstate),.sys_addr(sys_addr),.sdr_dq(sdr_dq),.sdr_dqm(sdr_dqm)); sdr_sig sdr_sig(.clk_i(clk_i),.rst_i(rst_i),.sys_addr(sys_addr),.istate(istate), .cstate(cstate),.sdr_cke(sdr_cke),.sdr_csn(sdr_csn),.sdr_rasn(sdr_rasn),.sdr_casn(sd r_casn),. sdr_wen(sdr_wen),.sdr_ba(sdr_ba),.sdr_addr(sdr_addr)); `endif endmodule