原创 sdram verilog程序

2010-12-24 11:33 5215 9 12 分类: FPGA/CPLD

sdram芯片用的是hy57v641620hgt-7,fpga用的是EP1C6Q240C8,晶振是50M,经过PLL倍频至125M,系统clk时钟是125M,sdram时钟相移-3ns


程序是根据特权的sdram程序和SOPC中sdram程序改写而成。


/*******************************************************************
*Project Name  :sdram
*Module  Name :sdram
*Target Device :EP1C6Q240C8
*Clkin   :50M
*Desisgner  :kang
*Date    :2010-12-01
*Version   :1.00
*Descriprion :sdram controller
*Additional Comments :  sdram controller works at 125M HZ.
*******************************************************************/
module sdram_self(
//input signals
input     clk,
input     rst,
input     wr_req,
input     rd_req,
input    [21:0] addr,   //from bus
input    [15:0] data_write, //from bus
//output signals
output    cs_n,
output     cas_n,
output     ras_n,
output     cke,
output reg [1:0] ba,
output reg [11:0] add,   //give sdram
output    we_n,
output   [1:0] dqm,
output    wr_ack,
output    rd_ack,
output     busy,
output  [15:0]  data_read,
output        wr_done,
output        rd_done,
//inout signals
inout    [15:0] dq  
    );


//Initial state machine parameters    
parameter  INIT_NOP =4'd0,
    INIT_PRE =4'd1,
    INIT_AR =4'd2,
    INIT_MRS =4'd3,
    INIT_CNT =4'd4,
    INIT_DONE=4'd5;


//Work state machine parameters
parameter WORK_IDLE =4'd0,
    WORK_ACTIVE =4'd1,
    WORK_READ =4'd2,
    WORK_RD  =4'd3,
    WORK_RWAIT =4'd4,
    WORK_WRITE =4'd5,
    WORK_WD  =4'd6,
    WORK_TDAL =4'd7,
    WORK_AR  =4'd8;


//Command parameters
parameter CMD_INIT   =5'b01111, //Initial after power on
    CMD_NOP   =5'b10111, //NOP command
    CMD_ACTIVE  =5'b10011, //ACTIVE command
    CMD_READ   =5'b10101, //READ command
    CMD_WRITE  =5'b10100, //WRITE command
    CMD_BURSTSTOP =5'b10110, //BURST stop
    CMD_PRECHARGE =5'b10010, //precharge
    CMD_AUTOREFRESH=5'b10001, //auto refersh
    CMD_LOADMODEREG=5'b10000; //load mode register
   
//timing parameters
parameter  TRP_CLK =4'd4,    //precharge
    TRFC_CLK =4'd6,    //refresh
    TMRD_CLK =4'd6,    //load mode register
    TRCD_CLK =4'd2,    //row to column delay
    TCL_CLK =4'd3,    //cas latency
    TREAD_CLK=4'd8,    //read
    TWRITE_CLK=4'd8,    //write
    TDAL_CLK =4'd3;    //after write,wait clock num


/**********************************************************************
******************from here starts the control code********************
***********************************************************************/



/***********************************************************************
//delay 200us after power on
//this counter depends on the work frequency
//default:125M HZ
***********************************************************************/


//counter_200us
reg [14:0] counter_200us;
always @(posedge clk or negedge rst)    
 begin
 if(!rst) counter_200us<=0;
 else if(counter_200us<15'd25000) counter_200us<=counter_200us+1'b1;
 end


//done_200us
wire done_200us;
assign done_200us=(counter_200us>=15'd25000);


/********************************************************************** 
//command assignments
//command is made up of cke,cs_n,ras_n,cas_n,we_n
//command's value is produced by the work state machine
**********************************************************************/


reg [4:0] command;
assign {cke,cs_n,ras_n,cas_n,we_n}=command; 


/**********************************************************************
//Initial state machine
//this state machine is only avaliable after power on,and only runs once
//when this state machine runs over,then the controller runs in the work state machine
//
***********************************************************************/


reg [3:0] init_nextstate; //next state
reg [3:0] init_state;  //current state
reg [4:0] init_counter; //this counter is used to make delay in the initial state machine
reg [4:0] init_cmd; //cmd in the initial state machine
reg [1:0] init_ba; //
reg [11:0] init_addr;//
reg [3:0] refresh_counter;
always @(posedge clk or negedge rst)
 begin
 if(!rst)       //
  begin
  init_cmd<=CMD_INIT;
  init_ba<=2'b11;
  init_addr<=12'hfff;
  init_state<=INIT_NOP;
  init_state<=INIT_NOP;
  init_counter<=0;
  refresh_counter<=0;
  end
 else
  begin
  case(init_state)
  INIT_NOP :     //wait 200us after power on, and then go the the next state
   begin
   init_cmd<=CMD_NOP;
   init_ba<=2'b11;
   init_addr<=12'hfff;
   if(done_200us) init_state<=INIT_PRE;
   end
  INIT_PRE :     //precharge
   begin
   init_cmd<=CMD_PRECHARGE;
   init_ba<=2'b11;
   init_addr<=12'hfff;
   init_counter<=TRP_CLK;
   init_state<=INIT_CNT;
   init_nextstate<=INIT_AR;
   end
  INIT_AR:     //auto refresh, in the initial state,we run auto refresh 3 times
   begin
   init_ba<=2'b11;
   init_addr<=12'hfff;
   init_counter<=TRFC_CLK;
   if(refresh_counter==4'h7)
     begin
     init_state<=INIT_MRS;
     end
   else
    begin
    refresh_counter<=refresh_counter+1'b1;
    init_cmd<=CMD_AUTOREFRESH;
    init_state<=INIT_CNT;
    end
   init_nextstate<=INIT_AR;
   end
  INIT_MRS :     //load the mode register
   begin
   init_cmd<=CMD_AUTOREFRESH;
   init_ba<=2'b00;
   init_addr<={
       2'b00,  //a11=0,a10=0;
       1'b0,   //a9,burst read and write
       2'b00,  //a8=0;a7=0;
       3'b011,  //cas latency=3
       1'b0,   //burst mode set
       3'b011  //burst data length set,here we use the length of 8
       };
   init_counter<=TRFC_CLK;
   init_state<=INIT_CNT;
   init_nextstate<=INIT_DONE;
   end
  INIT_CNT :      //init state machine counter, used to produce delay
   begin
   init_cmd<=CMD_NOP;
   init_ba<=2'b11;
   init_addr<=12'hfff;
   if(init_counter>4'd1) init_counter<=init_counter-1'b1;
   else init_state<=init_nextstate;
   end
  INIT_DONE:      //initial done
    init_state<=INIT_DONE;
  default:
   begin
   init_state<=INIT_NOP;
   init_ba<=2'b11;
   init_addr<=12'hfff;
   end
  endcase
  end
 end


wire sign_init_done;
assign sign_init_done=(init_state==INIT_DONE)?1'b1:1'b0;
 
/*******************************************************************************
//refresh counter 
//sdram need refresh every 64ms,and this chip has 4096 columns
//so we has to fresh every 15.625us
*******************************************************************************/


//counter_15us
reg [10:0] counter_15us;
always @(posedge clk or negedge rst)
 begin
 if(!rst) counter_15us<=0;
 else if(counter_15us>=11'd1875) counter_15us<=0;
 else counter_15us<=counter_15us+1'b1;
 end


//refresh request and answer back
reg refresh_req;  //refresh request
wire refresh_ack;  //refresh answer back
always @(posedge clk or negedge rst)
 begin
 if(!rst) refresh_req<=0;
 else if(counter_15us>=1875) refresh_req<=1'b1;
 else if(refresh_ack) refresh_req<=0;
 end


 
/******************************************************************************* 
//work state machine
//this state machine works at the normal time, including read, write and refresh
//when initial state machine runs over, this machine begin to run
//
*******************************************************************************/
reg [3:0] work_state;    //current state
reg [4:0] work_counter;    //work counter, used to make delay
reg wr_n;        //when write,wr_n=0;when read,wr_n=1;
reg oe;
always @(posedge clk or negedge rst)
 begin
 if(!rst)
  begin
  command<=CMD_INIT;
  ba<=2'b11;
  add=12'hfff;
  work_state<=WORK_IDLE;
  work_counter<=0;
  end
 else if(sign_init_done)//when initial state machine done, work state machine begin to run
  begin
  case(work_state)
  WORK_IDLE :     //in the idle state, we will enter autorefresh or active state as the next state
   begin
   command<=CMD_NOP;
   ba<=2'b11;
   add=12'hfff;
   work_counter<=0;
   if(refresh_req)
    begin
    work_state<=WORK_AR;
    end
   else if(wr_req)
    //begin
    //if((prior_rowadd==addr[21:8])&&is_prior_wr) work_state<=WORK_WRITE;
    //else
     begin
     work_state<=WORK_ACTIVE;     
     wr_n<=0;     
     end
    //end
   else if(rd_req)
    //begin
    //if((prior_rowadd==addr[21:8])&&is_prior_rd) work_state<=WORK_READ;
    //else
     begin
     work_state<=WORK_ACTIVE;
     wr_n<=1'b1;
     end
    //end
   else work_state<=WORK_IDLE;
   end
  WORK_ACTIVE :     //write the row address,and wait TRCD_CLK clks
   begin
   ba<=addr[21:20];
   add=addr[19:8];
   if(work_counter>=TRCD_CLK)
    begin
    if(wr_n) work_state<=WORK_READ;
    else work_state<=WORK_WRITE;
    work_counter<=0;
    end
   else
    begin
    if(work_counter==0) command<=CMD_ACTIVE;
    else command<=CMD_NOP;
    work_state<=WORK_ACTIVE;
    work_counter<=work_counter+1'b1;
    end
   end
  WORK_READ :     //read. wait TCL_CLK clks, then enter WORK_RD
   begin
   ba<=addr[21:20];
   add<={
     4'b0100,    //A10=1;allow precharge after write
     addr[7:0]   //column address
     };
   if(work_counter>=(TCL_CLK))
    begin
    work_state<=WORK_RD;
    work_counter<=0;
    end
   else
    begin
    work_state<=WORK_READ;
    work_counter<=work_counter+1'b1;
    end
   if(work_counter==0) command<=CMD_READ;
   else command<=CMD_NOP;
   end
  WORK_RD  :     //read data
   begin
   command<=CMD_NOP;
   if(work_counter>=(TREAD_CLK-1'b1))
    begin
    work_state<=WORK_RWAIT;
    work_counter<=0;
    end
   else
    begin
    work_state<=WORK_RD;
    work_counter<=work_counter+1'b1;
    end
   end
  WORK_RWAIT :     //read wait
   begin
   command<=CMD_NOP;
   if(work_counter>=(TRP_CLK))
    begin
    work_state<=WORK_IDLE;
    work_counter<=0;
    end
   else
    begin
    work_state<=WORK_RWAIT;
    work_counter<=work_counter+1'b1;
    end
   end
  WORK_WRITE :     //write
   begin
   command<=CMD_WRITE;
   ba<=addr[21:20];
   add<={
     4'b0100,    //A10=1;allow precharge after write
     addr[7:0]   //column address
     };
   work_state<=WORK_WD; 
   end
  WORK_WD  :     //write data
   begin
   command<=CMD_NOP;
   if(work_counter>=(TWRITE_CLK-1'b1))
    begin
    work_state<=WORK_TDAL;
    work_counter<=0;
    end
   else
    begin
    work_state<=WORK_WD;
    work_counter<=work_counter+1'b1;
    end
   end
  WORK_TDAL :     //write delay
   begin
   command<=CMD_NOP;
   if(work_counter>=TDAL_CLK)
    begin
    work_state<=WORK_IDLE;
    work_counter<=0;
    end
   else
    begin
    work_state<=WORK_TDAL;
    work_counter<=work_counter+1'b1;
    end
   end
  WORK_AR  :     //auto refresh
   begin
   if(work_counter==0) command<=CMD_AUTOREFRESH;
   else command<=CMD_NOP;
   ba<=2'b11;
   add<=12'hfff;
   if(work_counter==TRFC_CLK)
    begin
    work_state<=WORK_IDLE;
    work_counter<=0;
    end
   else
    begin
    work_state<=WORK_AR;
    work_counter<=work_counter+1'b1;
    end
   end
  default:
   begin
   command<=CMD_NOP;
   work_state<=WORK_IDLE;
   work_counter<=0;
   end
  endcase
  end
 else          //when in initial state, all parameters are equaled to the initial state
  begin
  command<=init_cmd;
  ba<=init_ba;
  add<=init_addr;
  work_counter<=0;
  end
 end


assign busy=(sign_init_done&&(work_state==WORK_IDLE))?1'b0:1'b1;
assign refresh_ack=(work_state==WORK_AR);
assign wr_ack=(work_state==WORK_WD);
assign rd_ack=(work_state==WORK_RD);
assign wr_done=(work_state==WORK_TDAL)&&(work_counter==5'd0);
assign rd_done=(work_state==WORK_RWAIT)&&(work_counter==5'd0);


assign data_read=dq;


assign dq=((work_state==WORK_WD)||(work_state==WORK_WRITE)||(work_state==WORK_TDAL))?data_write:16'hzzzz;


assign dqm=2'b00;
 
endmodule

PARTNER CONTENT

文章评论3条评论)

登录后参与讨论

用户425426 2012-11-18 14:14

你好 请问 你这个程序弄好了吗?

用户563794 2012-9-24 15:35

你好,请问 assign data_read=dq; assign dq=((work_state==WORK_WD)||(work_state==WORK_WRITE)||(work_state==WORK_TDAL))?data_write:16'hzzzz; 这两句是不是有点问题啊?后一句保证在写状态的时data_write的数据能赋给dq,但同时意味着只要不是在写状态,dq就等于16'hzzzz,即为高阻态,那么在读状态的时候,由于assign data_read=dq,那么data_read读到的数据就不可能是从SDRAM给出的数据,而是一直是高阻态,我觉得是这样的,请问我的理解有什么问题吗?谢谢,望不吝赐教!

用户377235 2012-9-24 15:28

你好,请问assign data_read=dq;这一句是不是有点问题啊? assign dq=((work_state==WORK_WD)||(work_state==WORK_WRITE)|| (work_state==WORK_TDAL))?data_write:16'hzzzz;后一句保证在写状态的时候data_write能给dq,但同时意味着只要不在写状态,dq就为高阻态,这就导致在读的时候data_read不可能读到dq的值,而是一直为高阻态,不知道我理解的是否有问题,望不吝赐教!
相关推荐阅读
用户282447 2011-01-19 17:05
stm32使用fsmc时地址移位问题
stm32平台使用fsmc时,当操作数据宽度为8位时,HADDR【25:0】与FSMC【25:0】对齐,当操作的数据为16位时,HADDR【25:1】与FSMC【24:0】对齐,HADDR【0】未接。...
用户282447 2011-01-05 19:42
verilog分频
fpga程序里经常会遇见给一个50 MHZ的clk,然后产生一个可变频率的clk‘。尤其是在电机控制中,加减速需要便频率,而fpga中除法又比较耗资源。今天看到一个程序,觉得思想不错,整理如下。   ...
用户282447 2011-01-01 23:47
2011,回顾从前
毕业第一年。    2010很快过去了,大学生活也已经成了历史,貌似很近,又貌似很远。    2011已经来临,是时候该回顾回顾自己大学至今都在做什么了。俗话说,男的把电脑当游戏机,女的把电脑当影碟机...
用户282447 2010-12-24 11:26
串口verilog程序
发一个自己写的串口程序,波特率115200,一位起始位,8个数据位,一个停止位接收采用8倍过采样。下面有4个module,uart是顶层模块,uart_rx是接收模块,uart_tx是发送模块,uar...
用户282447 2010-11-27 18:58
tft verilog驱动
       使用的TFT为群创7寸液晶屏AT070TN83,分辨率为800*480FPGA为ep1c6q240c8,晶振为50M       首先介绍一下TFT接口       1和2脚VLED,4...
我要评论
3
9
关闭 站长推荐上一条 /4 下一条