2018/7/26

受教于邓堪文老师,开始真真学习控制sdram

由于自己买的sdram模块是256的,原来老师的是128,所以边学边改,不知道最后好不好使,但是我有信心

一.sdram的初始化

sdram介绍啥的就不用了,上来就是干,简单粗暴。

1.下面是引脚说明,看不懂自己可以用百度翻译,需要注意的是红框内的地址引脚和行列地址是复用的,A0~A12是行地址,A0~8是列地址

简单说一下SDRAM的容量计算:数据位宽 *行地址*列地址*bank数,我们用的256有4个bank,就是:16*8192*512*4

基于fpga的256m的SDRAM控制器-LMLPHP

2.我的fpga是50m时钟,20ns一个周期,下图是初始化的时序图

sdram上电要延时至少100us,我们是延时200us,然后precharge(预充电)命令,隔tRP时间也就是一个时钟周期20ns进行第一次auto_refresh(自刷新),再隔tRC时间也就是四个时钟周期进行第二次auto_refresh命令,

又tRC时间进行mode_register(模式寄存器配置)。期间的NOP是空操作命令。还有就是这几个时间要看自己使用sdram的datasheet

基于fpga的256m的SDRAM控制器-LMLPHP

3.上面说的命令也是要去datasheet手册去找,对应CS,RAS,CAS,WE的操作

基于fpga的256m的SDRAM控制器-LMLPHP

4.模式配置对应datasheet ,根据红框addr:0_0000_0010_0010

基于fpga的256m的SDRAM控制器-LMLPHP

5.再来一张时序图

基于fpga的256m的SDRAM控制器-LMLPHP

6.该上源码了,应该没啥看不懂的吧

 `timescale     1ns/1ns

 module        tb_sdram_top;

 reg                sclk                ;
 reg                s_rst_n                ;

 //----------------------------------------------------------
 wire            sdram_clk            ;
 wire            sdram_cke            ;
 wire            sdram_cs_n            ;
 wire            sdram_cas_n            ;
 wire            sdram_ras_n            ;
 wire            sdram_we_n            ;
 :]    sdram_bank            ;
 :]    sdram_addr            ;
 :]    sdram_dqm            ;
 :]    sdram_dq            ;

 initial    begin
         sclk    =    ;
         s_rst_n    <=    ;
         #
         s_rst_n    <=    ;
 end

         sclk    =    ~sclk;

 sdram_top        sdram_top_inst(
         //system signals
         .sclk                    (sclk                ),
         .s_rst_n                (s_rst_n            ),
         //SDRAM Interfaces
         .sdram_clk                (sdram_clk            ),
         .sdram_cke                (sdram_cke            ),
         .sdram_cs_n                (sdram_cs_n            ),
         .sdram_cas_n            (sdram_cas_n        ),
         .sdram_ras_n            (sdram_ras_n        ),
         .sdram_we_n                (sdram_we_n            ),
         .sdram_bank                (sdram_bank            ),
         .sdram_addr                (sdram_addr            ),
         .sdram_dqm                (sdram_dqm            ),
         .sdram_dq                (sdram_dq            )
 );

 sdram_model_plus     sdram_model_plus_inst(
         .Dq                      (sdram_dq            ),
         .Addr                    (sdram_addr        ),
         .Ba                      (sdram_bank        ),
         .Clk                     (sdram_clk            ),
         .Cke                     (sdram_cke            ),
         .Cs_n                    (sdram_cs_n        ),
         .Ras_n                   (sdram_ras_n        ),
         .Cas_n                   (sdram_cas_n        ),
         .We_n                    (sdram_we_n        ),
         .Dqm                     (sdram_dqm            ),
         .Debug                   ('b1                )
 );

 endmodule

tb_sdram_top

 module sdram_ini(
             //systejm signal
             input                sclk            ,
             input                s_rst_n            ,
             //others
             :]    cmd_reg            ,
             :]    sdram_addr        ,
             output                flag_ini_end
 );

 //==============================================================================\
 //*********************Define Parameter and Internal Signal ********************
 //==============================================================================/

     ;
 //SDRAM Command
 'b0111    ;
 'b0010    ;
 'b0001    ;
 'b0000    ;

 :]    cnt_200us                    ;
 wire                flag_200us                    ;
 :]    cnt_cmd                        ;

 //=============================================================================\
 //********************** Main Code    ***************************************
 //=============================================================================/

 always @(posedge sclk or negedge s_rst_n) begin
         'b0)
                 cnt_200us <= 'd0;
         'b0)
                 cnt_200us <= cnt_200us + 'b1;
 end

 always @(posedge sclk or negedge s_rst_n) begin
         'b0)
                 cnt_cmd        <=        'd0;
         'b1 && flag_ini_end == 1'b0)
                 cnt_cmd        <=         cnt_cmd    +    'b1;
 end

 //cmd_reg
 always @(posedge sclk or negedge s_rst_n ) begin
         'b0)
                 cmd_reg <= NOP;
         'b1)
                 case(cnt_cmd)
                         :    cmd_reg    <=    PRE        ;
                         :    cmd_reg <=  AREF    ;
                         :    cmd_reg <=    AREF    ;
                         :    cmd_reg    <=    MSET    ;
                         default    :    cmd_reg <= NOP ;
                 endcase
 end
 'b0;
 'b0_0000_0011_0010 : 13'b0_0100_0000_0000;
 'b1    :    1'b0;

 endmodule

sdram_init

 module sdram_top(
         //system signals
         input                    sclk            ,
         input                    s_rst_n            ,
         //SDRAM Interfaces
         output    wire            sdram_clk        ,
         output    wire            sdram_cke        ,
         output    wire            sdram_cs_n        ,
         output    wire            sdram_cas_n        ,
         output    wire            sdram_ras_n        ,
         output    wire            sdram_we_n        ,
         :]    sdram_bank        ,
         :]    sdram_addr        ,
         :]    sdram_dqm        ,
         :]    sdram_dq
 );

 //==============================================================================\
 //*********************Define Parameter and Internal Signal ********************
 //==============================================================================/
 //init module
 wire                    flag_ini_end            ;
 :]            init_cmd                ;
 :]            init_addr                ;

 //=============================================================================\
 //********************** Main Code    ***************************************
 //=============================================================================/
 'b1;
 assign    sdram_addr        =   init_addr;
 assign    {sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n}    =    init_cmd ;
 'd0;
 assign    sdram_clk         =     ~sclk;

 sdram_ini        sdram_ini_inst(
             //systejm signal
             .sclk                (sclk            ),
             .s_rst_n            (s_rst_n        ),
             //others
             .cmd_reg            (init_cmd        ),
             .sdram_addr            (init_addr        ),
             .flag_ini_end       (flag_ini_end    )
 );

 endmodule

sdram_top

这用了一个sdram仿真模型,堪文老师是128的,我的256的不能用,但是我改好了

 /***************************************************************************************
 作者:    李晟
 2003-08-27    V0.1    李晟

  添加内存模块倒空功能,在外部需要创建事件:sdram_r ,本SDRAM的内容将会按Bank 顺序damp out 至文件
  sdram_data.txt 中
 ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××*/
 //2004-03-04    陈乃奎    修改原程序中将BANK的数据转存入TXT文件的格式
 //2004-03-16    陈乃奎    修改SDRAM 的初始化数据
 //2004/04/06    陈乃奎    将SDRAM的操作命令以字符形式表示,以便用MODELSIM监视
 //2004/04/19    陈乃奎    修改参数 parameter tAC  =   8;
 //2010/09/17    罗瑶    修改sdram的大小,数据位宽,dqm宽度;
 /****************************************************************************************
 *
 *    File Name:  sdram_model.V
 *      Version:  0.0f
 *         Date:  July 8th, 1999
 *        Model:  BUS Functional
 *    Simulator:  Model Technology (PC version 5.2e PE)
 *
 * Dependencies:  None
 *
 *       Author:  Son P. Huynh
 *        Email:  [email protected]
 *        Phone:  (208) 368-3825
 *      Company:  Micron Technology, Inc.
 *        Model:  sdram_model (1Meg x 16 x 4 Banks)
 *
 *  Description:  64Mb SDRAM Verilog model
 *
 *   Limitation:  - Doesn't check for 4096 cycle refresh
 *
 *         Note:  - Set simulator resolution to "ps" accuracy
 *                - Set Debug = 0 to disable $display messages
 *
 *   Disclaimer:  THESE DESIGNS ARE PROVIDED "AS IS" WITH NO WARRANTY
 *                WHATSOEVER AND MICRON SPECIFICALLY DISCLAIMS ANY
 *                IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
 *                A PARTICULAR PURPOSE, OR AGAINST INFRINGEMENT.
 *
 *                Copyright ?1998 Micron Semiconductor Products, Inc.
 *                All rights researved
 *
 * Rev   Author          Phone         Date        Changes
 * ----  ----------------------------  ----------  ---------------------------------------
 * 0.0f  Son Huynh       208-368-3825  07/08/1999  - Fix tWR = 1 Clk + 7.5 ns (Auto)
 *       Micron Technology Inc.                    - Fix tWR = 15 ns (Manual)
 *                                                 - Fix tRP (Autoprecharge to AutoRefresh)
 *
 * 0.0a  Son Huynh       208-368-3825  05/13/1998  - First Release (from 64Mb rev 0.0e)
 *       Micron Technology Inc.
 ****************************************************************************************/

 `timescale 1ns / 100ps

 module sdram_model_plus (Dq, Addr, Ba, Clk, Cke, Cs_n, Ras_n, Cas_n, We_n, Dqm,Debug);

     ;
     ;
     ;
     ** -;//1 Meg

      : ] Dq;
      : ] Addr;
      : ] Ba;
     input                         Clk;
     input                         Cke;
     input                         Cs_n;
     input                         Ras_n;
     input                         Cas_n;
     input                         We_n;
      : ] Dqm;          //高低各8bit
     //added by xzli
     input              Debug;

      : ] Bank0 [ : mem_sizes];//存储器类型数据
      : ] Bank1 [ : mem_sizes];
      : ] Bank2 [ : mem_sizes];
      : ] Bank3 [ : mem_sizes];

      : ] Bank_addr [ : ];                // Bank Address Pipeline
      : ] Col_addr [ : ];                 // Column Address Pipeline
      : ] Command [ : ];                  // Command Operation Pipeline
      : ] Dqm_reg0, Dqm_reg1;               // DQM Operation Pipeline
      : ] B0_row_addr, B1_row_addr, B2_row_addr, B3_row_addr;

      : ] Mode_reg;
      : ] Dq_reg, Dq_dqm;
      : ] Col_temp, Burst_counter;

     reg                           Act_b0, Act_b1, Act_b2, Act_b3;   // Bank Activate
     reg                           Pc_b0, Pc_b1, Pc_b2, Pc_b3;       // Bank Precharge

      : ] Bank_precharge     [ : ];       // Precharge Command
      : ];       // Addr[10] = 1 (All banks)
      : ];       // RW AutoPrecharge (Bank)
      : ];       // R  AutoPrecharge
      : ];       //  W AutoPrecharge
      : ];       // RW AutoPrecharge (Counter)
      : ];       // RW Interrupt Read with Auto Precharge
      : ];       // RW Interrupt Write with Auto Precharge

     reg                           Data_in_enable;
     reg                           Data_out_enable;

      : ] Bank, Previous_bank;
      : ] Row;
      : ] Col, Col_brst;

     // Internal system clock
     reg                           CkeZ, Sys_clk;

     :]    dd;

     // Commands Decode
     wire      Active_enable    = ~Cs_n & ~Ras_n &  Cas_n &  We_n;
     wire      Aref_enable      = ~Cs_n & ~Ras_n & ~Cas_n &  We_n;
     wire      Burst_term       = ~Cs_n &  Ras_n &  Cas_n & ~We_n;
     wire      Mode_reg_enable  = ~Cs_n & ~Ras_n & ~Cas_n & ~We_n;
     wire      Prech_enable     = ~Cs_n & ~Ras_n &  Cas_n & ~We_n;
     wire      Read_enable      = ~Cs_n &  Ras_n & ~Cas_n &  We_n;
     wire      Write_enable     = ~Cs_n &  Ras_n & ~Cas_n & ~We_n;

     // Burst Length Decode
     ] & ~Mode_reg[] & ~Mode_reg[];
     ] & ~Mode_reg[] &  Mode_reg[];
     ] &  Mode_reg[] & ~Mode_reg[];
     ] &  Mode_reg[] &  Mode_reg[];

     // CAS Latency Decode
     ] &  Mode_reg[] & ~Mode_reg[];
     ] &  Mode_reg[] &  Mode_reg[];

     // Write Burst Mode
     ];

     wire      Debug;        // Debug messages : 1 = On; 0 = Off
     wire      Dq_chk           = Sys_clk & Data_in_enable;      // Check setup/hold time for DQ

     :]    mem_d;

     event    sdram_r,sdram_w,compare;

     assign    Dq               = Dq_reg;                        // DQ buffer

     // Commands Operation
     `define   ACT
     `define   NOP
     `define   READ
     `define   READ_A
     `define   WRITE
     `define   WRITE_A
     `define   PRECH
     `define   A_REF
     `define   BST
     `define   LMR

 //    // Timing Parameters for -75 (PC133) and CAS Latency = 2
 //    parameter tAC  =   8;    //test 6.5
 //    parameter tHZ  =   7.0;
 //    parameter tOH  =   2.7;
 //    parameter tMRD =   2.0;     // 2 Clk Cycles
 //    parameter tRAS =  44.0;
 //    parameter tRC  =  66.0;
 //    parameter tRCD =  20.0;
 //    parameter tRP  =  20.0;
 //    parameter tRRD =  15.0;
 //    parameter tWRa =   7.5;     // A2 Version - Auto precharge mode only (1 Clk + 7.5 ns)
 //    parameter tWRp =  0.0;     // A2 Version - Precharge mode only (15 ns)

     // Timing Parameters for -7 (PC143) and CAS Latency = 3
     parameter tAC  =   6.5;    //test 6.5
     parameter tHZ  =   5.5;
     ;
     parameter tMRD =   2.0;     // 2 Clk Cycles
     parameter tRAS =  48.0;
     parameter tRC  =  70.0;
     parameter tRCD =  20.0;
     parameter tRP  =  20.0;
     parameter tRRD =  14.0;
     parameter tWRa =   7.5;     // A2 Version - Auto precharge mode only (1 Clk + 7.5 ns)
     parameter tWRp =  0.0;     // A2 Version - Precharge mode only (15 ns)

     // Timing Check variable
     integer   MRD_chk;
      : ];
      : ];
     time      RC_chk, RRD_chk;
     time      RAS_chk0, RAS_chk1, RAS_chk2, RAS_chk3;
     time      RCD_chk0, RCD_chk1, RCD_chk2, RCD_chk3;
     time      RP_chk0, RP_chk1, RP_chk2, RP_chk3;

     integer    test_file;

     //*****display the command of the sdram**************************************

     'b0000;
     'b0001;
     'b0011;
     'b0010;
     'b0010;
     'b0100;
     'b0100;
     'b0101;
     'b0101;
     'b0110;
     'b0111;
     'b1111;

     :]    sdram_control;
     reg            cke_temp;
     *:]    sdram_command;

     always@(posedge Clk)
     cke_temp<=Cke;

     assign    sdram_control={Cs_n,Ras_n,Cas_n,We_n};

     always@(sdram_control or cke_temp)
     begin
         case(sdram_control)
             Mode_Reg_Set:    sdram_command<="Mode_Reg_Set";
             Auto_Refresh:    sdram_command<="Auto_Refresh";
             Row_Active:    sdram_command<="Row_Active";
             Pre_Charge:    sdram_command<="Pre_Charge";
             Burst_Stop:    sdram_command<="Burst_Stop";
             Dsel:        sdram_command<="Dsel";

             Write:        )
                         sdram_command<="Write";
                     else
                         sdram_command<="Write_suspend";

             Read:        )
                         sdram_command<="Read";
                     else
                         sdram_command<="Read_suspend";

             Nop:        )
                         sdram_command<="Nop";
                     else
                         sdram_command<="Self_refresh";

             default:    sdram_command<="Power_down";
         endcase
     end

     //*****************************************************

     initial
         begin
         //test_file=$fopen("test_file.txt");
     end

     initial
         begin
         Dq_reg = {data_bits{'bz}};
         {Data_in_enable, Data_out_enable} = ;
         {Act_b0, Act_b1, Act_b2, Act_b3} = 'b0000;
         {Pc_b0, Pc_b1, Pc_b2, Pc_b3} = 'b0000;
         {WR_chk[], WR_chk[], WR_chk[], WR_chk[]} = ;
         {WR_counter[], WR_counter[], WR_counter[], WR_counter[]} = ;
         {RW_interrupt_read[], RW_interrupt_read[], RW_interrupt_read[], RW_interrupt_read[]} = ;
         {RW_interrupt_write[], RW_interrupt_write[], RW_interrupt_write[], RW_interrupt_write[]} = ;
         {MRD_chk, RC_chk, RRD_chk} = ;
         {RAS_chk0, RAS_chk1, RAS_chk2, RAS_chk3} = ;
         {RCD_chk0, RCD_chk1, RCD_chk2, RCD_chk3} = ;
         {RP_chk0, RP_chk1, RP_chk2, RP_chk3} = ;
         $timeformat (-, , );
         //$readmemh("bank0.txt", Bank0);
         //$readmemh("bank1.txt", Bank1);
         //$readmemh("bank2.txt", Bank2);
         //$readmemh("bank3.txt", Bank3);
 /*
        for(dd=0;dd<=mem_sizes;dd=dd+1)
             begin
                 Bank0[dd]=dd[data_bits - 1 : 0];
                 Bank1[dd]=dd[data_bits - 1 : 0]+1;
                 Bank2[dd]=dd[data_bits - 1 : 0]+2;
                 Bank3[dd]=dd[data_bits - 1 : 0]+3;
             end
 */
       initial_sdram();
       end

         task    initial_sdram;

          input        data_sign;
          :]    data_sign;

                ;dd<=mem_sizes;dd=dd+)
             begin
                 mem_d = {data_sign,data_sign,data_sign,data_sign,data_sign,data_sign,data_sign,data_sign};
                 )
                     begin
                         Bank0[dd]=mem_d[:];
                         Bank1[dd]=mem_d[:];
                         Bank2[dd]=mem_d[:];
                         Bank3[dd]=mem_d[:];
                     end
                 )
                     begin
                         Bank0[dd]=mem_d[:];
                         Bank1[dd]=mem_d[:];
                         Bank2[dd]=mem_d[:];
                         Bank3[dd]=mem_d[:];
                     end
             end

                endtask

     // System clock generator
     always
         begin
                @(posedge Clk)
                    begin
                         Sys_clk = CkeZ;
                         CkeZ = Cke;
                 end
             @(negedge Clk)
                 begin
                         Sys_clk = 'b0;
                 end
         end

     always @ (posedge Sys_clk) begin
         // Internal Commamd Pipelined
         Command[] = Command[];
         Command[] = Command[];
         Command[] = Command[];
         Command[] = `NOP;

         Col_addr[] = Col_addr[];
         Col_addr[] = Col_addr[];
         Col_addr[] = Col_addr[];
         Col_addr[] = {col_bits{'b0}};

         Bank_addr[] = Bank_addr[];
         Bank_addr[] = Bank_addr[];
         Bank_addr[] = Bank_addr[];
         Bank_addr[] = 'b0;

         Bank_precharge[] = Bank_precharge[];
         Bank_precharge[] = Bank_precharge[];
         Bank_precharge[] = Bank_precharge[];
         Bank_precharge[] = 'b0;

         A10_precharge[] = A10_precharge[];
         A10_precharge[] = A10_precharge[];
         A10_precharge[] = A10_precharge[];
         A10_precharge[] = 'b0;

         // Dqm pipeline for Read
         Dqm_reg0 = Dqm_reg1;
         Dqm_reg1 = Dqm;

         // Read or Write with Auto Precharge Counter
         ] == 'b1) begin
             Count_precharge[] = Count_precharge[] + ;
         end
         ] == 'b1) begin
             Count_precharge[] = Count_precharge[] + ;
         end
         ] == 'b1) begin
             Count_precharge[] = Count_precharge[] + ;
         end
         ] == 'b1) begin
             Count_precharge[] = Count_precharge[] + ;
         end

         // tMRD Counter
         MRD_chk = MRD_chk + ;

         // tWR Counter for Write
         WR_counter[] = WR_counter[] + ;
         WR_counter[] = WR_counter[] + ;
         WR_counter[] = WR_counter[] + ;
         WR_counter[] = WR_counter[] + ;

         // Auto Refresh
         'b1) begin
             if (Debug) $display ("at time %t AREF : Auto Refresh", $time);
             // Auto Refresh to Auto Refresh
             if (($time - RC_chk < tRC)&&Debug) begin
                 $display ("at time %t ERROR: tRC violation during Auto Refresh", $time);
             end
             // Precharge to Auto Refresh
             if (($time - RP_chk0 < tRP || $time - RP_chk1 < tRP || $time - RP_chk2 < tRP || $time - RP_chk3 < tRP)&&Debug) begin
                 $display ("at time %t ERROR: tRP violation during Auto Refresh", $time);
             end
             // Precharge to Refresh
             'b0 || Pc_b3 == 1'b0) begin
                 $display ("at time %t ERROR: All banks must be Precharge before Auto Refresh", $time);
             end
             // Record Current tRC time
             RC_chk = $time;
         end

         // Load Mode Register
         'b1) begin
             // Decode CAS Latency, Burst Length, Burst Type, and Write Burst Mode
             'b1 && Pc_b3 == 1'b1) begin
                 Mode_reg = Addr;
                 if (Debug) begin
                     $display ("at time %t LMR  : Load Mode Register", $time);
                     // CAS Latency
                      : ] == 'b010)
                         $display ("                            CAS Latency      = 2");
                      : ] == 'b011)
                         $display ("                            CAS Latency      = 3");
                     else
                         $display ("                            CAS Latency      = Reserved");
                     // Burst Length
                      : ] == 'b000)
                         $display ("                            Burst Length     = 1");
                      : ] == 'b001)
                         $display ("                            Burst Length     = 2");
                      : ] == 'b010)
                         $display ("                            Burst Length     = 4");
                      : ] == 'b011)
                         $display ("                            Burst Length     = 8");
                      : ] == 'b0111)
                         $display ("                            Burst Length     = Full");
                     else
                         $display ("                            Burst Length     = Reserved");
                     // Burst Type
                     ] == 'b0)
                         $display ("                            Burst Type       = Sequential");
                     ] == 'b1)
                         $display ("                            Burst Type       = Interleaved");
                     else
                         $display ("                            Burst Type       = Reserved");
                     // Write Burst Mode
                     ] == 'b0)
                         $display ("                            Write Burst Mode = Programmed Burst Length");
                     ] == 'b1)
                         $display ("                            Write Burst Mode = Single Location Access");
                     else
                         $display ("                            Write Burst Mode = Reserved");
                 end
             end else begin
                 $display ("at time %t ERROR: all banks must be Precharge before Load Mode Register", $time);
             end
             // REF to LMR
             if ($time - RC_chk < tRC) begin
                 $display ("at time %t ERROR: tRC violation during Load Mode Register", $time);
             end
             // LMR to LMR
             if (MRD_chk < tMRD) begin
                 $display ("at time %t ERROR: tMRD violation during Load Mode Register", $time);
             end
             MRD_chk = ;
         end

         // Active Block (Latch Bank Address and Row Address)
         'b1) begin
             'b00 && Pc_b0 == 1'b1) begin
                 {Act_b0, Pc_b0} = 'b10;
                 B0_row_addr = Addr [addr_bits -  : ];
                 RCD_chk0 = $time;
                 RAS_chk0 = $time;
                 if (Debug) $display ("at time %t ACT  : Bank = 0 Row = %d", $time, Addr);
                 // Precharge to Activate Bank 0
                 if ($time - RP_chk0 < tRP) begin
                     $display ("at time %t ERROR: tRP violation during Activate bank 0", $time);
                 end
             'b01 && Pc_b1 == 1'b1) begin
                 {Act_b1, Pc_b1} = 'b10;
                 B1_row_addr = Addr [addr_bits -  : ];
                 RCD_chk1 = $time;
                 RAS_chk1 = $time;
                 if (Debug) $display ("at time %t ACT  : Bank = 1 Row = %d", $time, Addr);
                 // Precharge to Activate Bank 1
                 if ($time - RP_chk1 < tRP) begin
                     $display ("at time %t ERROR: tRP violation during Activate bank 1", $time);
                 end
             'b10 && Pc_b2 == 1'b1) begin
                 {Act_b2, Pc_b2} = 'b10;
                 B2_row_addr = Addr [addr_bits -  : ];
                 RCD_chk2 = $time;
                 RAS_chk2 = $time;
                 if (Debug) $display ("at time %t ACT  : Bank = 2 Row = %d", $time, Addr);
                 // Precharge to Activate Bank 2
                 if ($time - RP_chk2 < tRP) begin
                     $display ("at time %t ERROR: tRP violation during Activate bank 2", $time);
                 end
             'b11 && Pc_b3 == 1'b1) begin
                 {Act_b3, Pc_b3} = 'b10;
                 B3_row_addr = Addr [addr_bits -  : ];
                 RCD_chk3 = $time;
                 RAS_chk3 = $time;
                 if (Debug) $display ("at time %t ACT  : Bank = 3 Row = %d", $time, Addr);
                 // Precharge to Activate Bank 3
                 if ($time - RP_chk3 < tRP) begin
                     $display ("at time %t ERROR: tRP violation during Activate bank 3", $time);
                 end
             'b00 && Pc_b0 == 1'b0) begin
                 $display ("at time %t ERROR: Bank 0 is not Precharged.", $time);
             'b01 && Pc_b1 == 1'b0) begin
                 $display ("at time %t ERROR: Bank 1 is not Precharged.", $time);
             'b10 && Pc_b2 == 1'b0) begin
                 $display ("at time %t ERROR: Bank 2 is not Precharged.", $time);
             'b11 && Pc_b3 == 1'b0) begin
                 $display ("at time %t ERROR: Bank 3 is not Precharged.", $time);
             end
             // Active Bank A to Active Bank B
             if ((Previous_bank != Ba) && ($time - RRD_chk < tRRD)) begin
                 $display ("at time %t ERROR: tRRD violation during Activate bank = %d", $time, Ba);
             end
             // Load Mode Register to Active
             if (MRD_chk < tMRD ) begin
                 $display ("at time %t ERROR: tMRD violation during Activate bank = %d", $time, Ba);
             end
             // Auto Refresh to Activate
             if (($time - RC_chk < tRC)&&Debug) begin
                 $display ("at time %t ERROR: tRC violation during Activate bank = %d", $time, Ba);
             end
             // Record variables for checking violation
             RRD_chk = $time;
             Previous_bank = Ba;
         end

         // Precharge Block
         'b1) begin
             ] == 'b1) begin
                 {Pc_b0, Pc_b1, Pc_b2, Pc_b3} = 'b1111;
                 {Act_b0, Act_b1, Act_b2, Act_b3} = 'b0000;
                 RP_chk0 = $time;
                 RP_chk1 = $time;
                 RP_chk2 = $time;
                 RP_chk3 = $time;
                 if (Debug) $display ("at time %t PRE  : Bank = ALL",$time);
                 // Activate to Precharge all banks
                 if (($time - RAS_chk0 < tRAS) || ($time - RAS_chk1 < tRAS) ||
                     ($time - RAS_chk2 < tRAS) || ($time - RAS_chk3 < tRAS)) begin
                     $display ("at time %t ERROR: tRAS violation during Precharge all bank", $time);
                 end
                 // tWR violation check for write
                 ] < tWRp) || ($] < tWRp) ||
                     ($] < tWRp) || ($] < tWRp)) begin
                     $display ("at time %t ERROR: tWR violation during Precharge all bank", $time);
                 end
             ] == 'b0) begin
                 'b00) begin
                     {Pc_b0, Act_b0} = 'b10;
                     RP_chk0 = $time;
                     if (Debug) $display ("at time %t PRE  : Bank = 0",$time);
                     // Activate to Precharge Bank 0
                     if ($time - RAS_chk0 < tRAS) begin
                         $display ("at time %t ERROR: tRAS violation during Precharge bank 0", $time);
                     end
                 'b01) begin
                     {Pc_b1, Act_b1} = 'b10;
                     RP_chk1 = $time;
                     if (Debug) $display ("at time %t PRE  : Bank = 1",$time);
                     // Activate to Precharge Bank 1
                     if ($time - RAS_chk1 < tRAS) begin
                         $display ("at time %t ERROR: tRAS violation during Precharge bank 1", $time);
                     end
                 'b10) begin
                     {Pc_b2, Act_b2} = 'b10;
                     RP_chk2 = $time;
                     if (Debug) $display ("at time %t PRE  : Bank = 2",$time);
                     // Activate to Precharge Bank 2
                     if ($time - RAS_chk2 < tRAS) begin
                         $display ("at time %t ERROR: tRAS violation during Precharge bank 2", $time);
                     end
                 'b11) begin
                     {Pc_b3, Act_b3} = 'b10;
                     RP_chk3 = $time;
                     if (Debug) $display ("at time %t PRE  : Bank = 3",$time);
                     // Activate to Precharge Bank 3
                     if ($time - RAS_chk3 < tRAS) begin
                         $display ("at time %t ERROR: tRAS violation during Precharge bank 3", $time);
                     end
                 end
                 // tWR violation check for write
                 if ($time - WR_chk[Ba] < tWRp) begin
                     $display ("at time %t ERROR: tWR violation during Precharge bank %d", $time, Ba);
                 end
             end
             // Terminate a Write Immediately (if same bank or all banks)
             'b1 && (Bank == Ba || Addr[10] == 1'b1)) begin
                 Data_in_enable = 'b0;
             end
             // Precharge Command Pipeline for Read
             'b1) begin
                 Command[] = `PRECH;
                 Bank_precharge[] = Ba;
                 A10_precharge[] = Addr[];
             'b1) begin
                 Command[] = `PRECH;
                 Bank_precharge[] = Ba;
                 A10_precharge[] = Addr[];
             end
         end

         // Burst terminate
         'b1) begin
             // Terminate a Write Immediately
             'b1) begin
                 Data_in_enable = 'b0;
             end
             // Terminate a Read Depend on CAS Latency
             'b1) begin
                 Command[] = `BST;
             'b1) begin
                 Command[] = `BST;
             end
             if (Debug) $display ("at time %t BST  : Burst Terminate",$time);
         end

         // Read, Write, Column Latch
         'b1 || Write_enable == 1'b1) begin
             // Check to see if bank is open (ACT)
             'b01 && Pc_b1 == 1'b1) ||
                 (Ba == 'b11 && Pc_b3 == 1'b1)) begin
                 $display("at time %t ERROR: Cannot Read or Write - Bank %d is not Activated", $time, Ba);
             end
             // Activate to Read or Write
             'b00) && ($time - RCD_chk0 < tRCD))
                 $display("at time %t ERROR: tRCD violation during Read or Write to Bank 0", $time);
             'b01) && ($time - RCD_chk1 < tRCD))
                 $display("at time %t ERROR: tRCD violation during Read or Write to Bank 1", $time);
             'b10) && ($time - RCD_chk2 < tRCD))
                 $display("at time %t ERROR: tRCD violation during Read or Write to Bank 2", $time);
             'b11) && ($time - RCD_chk3 < tRCD))
                 $display("at time %t ERROR: tRCD violation during Read or Write to Bank 3", $time);
             // Read Command
             'b1) begin
                 // CAS Latency pipeline
                 'b1) begin
                     ] == 'b1) begin
                         Command[] = `READ_A;
                     end else begin
                         Command[] = `READ;
                     end
                     Col_addr[] = Addr;
                     Bank_addr[] = Ba;
                 'b1) begin
                     ] == 'b1) begin
                         Command[] = `READ_A;
                     end else begin
                         Command[] = `READ;
                     end
                     Col_addr[] = Addr;
                     Bank_addr[] = Ba;
                 end

                 // Read interrupt Write (terminate Write immediately)
                 'b1) begin
                     Data_in_enable = 'b0;
                 end

             // Write Command
             'b1) begin
                 ] == 'b1) begin
                     Command[] = `WRITE_A;
                 end else begin
                     Command[] = `WRITE;
                 end
                 Col_addr[] = Addr;
                 Bank_addr[] = Ba;

                 // Write interrupt Write (terminate Write immediately)
                 'b1) begin
                     Data_in_enable = 'b0;
                 end

                 // Write interrupt Read (terminate Read immediately)
                 'b1) begin
                     Data_out_enable = 'b0;
                 end
             end

             // Interrupting a Write with Autoprecharge
             'b1 && Write_precharge[Bank] == 1'b1) begin
                 RW_interrupt_write[Bank] = 'b1;
                 if (Debug) $display ("at time %t NOTE : Read/Write Bank %d interrupt Write Bank %d with Autoprecharge", $time, Ba, Bank);
             end

             // Interrupting a Read with Autoprecharge
             'b1 && Read_precharge[Bank] == 1'b1) begin
                 RW_interrupt_read[Bank] = 'b1;
                 if (Debug) $display ("at time %t NOTE : Read/Write Bank %d interrupt Read Bank %d with Autoprecharge", $time, Ba, Bank);
             end

             // Read or Write with Auto Precharge
             ] == 'b1) begin
                 Auto_precharge[Ba] = 'b1;
                 Count_precharge[Ba] = ;
                 'b1) begin
                     Read_precharge[Ba] = 'b1;
                 'b1) begin
                     Write_precharge[Ba] = 'b1;
                 end
             end
         end

         //  Read with Auto Precharge Calculation
         //      The device start internal precharge:
         //          1.  CAS Latency - 1 cycles before last burst
         //      and 2.  Meet minimum tRAS requirement
         //       or 3.  Interrupt by a Read or Write (with or without AutoPrecharge)
         ] == 'b1) && (Read_precharge[0] == 1'b1)) begin
             if ((($time - RAS_chk0 >= tRAS) &&                                                      // Case 2
                 ((Burst_length_1 == 'b1 && Count_precharge[0] >= 1) ||                             // Case 1
                  (Burst_length_2 == 'b1 && Count_precharge[0] >= 2) ||
                  (Burst_length_4 == 'b1 && Count_precharge[0] >= 4) ||
                  (Burst_length_8 == 'b1 && Count_precharge[0] >= 8))) ||
                  (RW_interrupt_read[] == 'b1)) begin                                              // Case 3
                     Pc_b0 = 'b1;
                     Act_b0 = 'b0;
                     RP_chk0 = $time;
                     Auto_precharge[] = 'b0;
                     Read_precharge[] = 'b0;
                     RW_interrupt_read[] = 'b0;
                     if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 0", $time);
             end
         end
         ] == 'b1) && (Read_precharge[1] == 1'b1)) begin
             if ((($time - RAS_chk1 >= tRAS) &&
                 ((Burst_length_1 == 'b1 && Count_precharge[1] >= 1) ||
                  (Burst_length_2 == 'b1 && Count_precharge[1] >= 2) ||
                  (Burst_length_4 == 'b1 && Count_precharge[1] >= 4) ||
                  (Burst_length_8 == 'b1 && Count_precharge[1] >= 8))) ||
                  (RW_interrupt_read[] == 'b1)) begin
                     Pc_b1 = 'b1;
                     Act_b1 = 'b0;
                     RP_chk1 = $time;
                     Auto_precharge[] = 'b0;
                     Read_precharge[] = 'b0;
                     RW_interrupt_read[] = 'b0;
                     if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 1", $time);
             end
         end
         ] == 'b1) && (Read_precharge[2] == 1'b1)) begin
             if ((($time - RAS_chk2 >= tRAS) &&
                 ((Burst_length_1 == 'b1 && Count_precharge[2] >= 1) ||
                  (Burst_length_2 == 'b1 && Count_precharge[2] >= 2) ||
                  (Burst_length_4 == 'b1 && Count_precharge[2] >= 4) ||
                  (Burst_length_8 == 'b1 && Count_precharge[2] >= 8))) ||
                  (RW_interrupt_read[] == 'b1)) begin
                     Pc_b2 = 'b1;
                     Act_b2 = 'b0;
                     RP_chk2 = $time;
                     Auto_precharge[] = 'b0;
                     Read_precharge[] = 'b0;
                     RW_interrupt_read[] = 'b0;
                     if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 2", $time);
             end
         end
         ] == 'b1) && (Read_precharge[3] == 1'b1)) begin
             if ((($time - RAS_chk3 >= tRAS) &&
                 ((Burst_length_1 == 'b1 && Count_precharge[3] >= 1) ||
                  (Burst_length_2 == 'b1 && Count_precharge[3] >= 2) ||
                  (Burst_length_4 == 'b1 && Count_precharge[3] >= 4) ||
                  (Burst_length_8 == 'b1 && Count_precharge[3] >= 8))) ||
                  (RW_interrupt_read[] == 'b1)) begin
                     Pc_b3 = 'b1;
                     Act_b3 = 'b0;
                     RP_chk3 = $time;
                     Auto_precharge[] = 'b0;
                     Read_precharge[] = 'b0;
                     RW_interrupt_read[] = 'b0;
                     if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 3", $time);
             end
         end

         // Internal Precharge or Bst
         ] == `PRECH) begin                         // Precharge terminate a read with same bank or all banks
             ] == Bank || A10_precharge[] == 'b1) begin
                 'b1) begin
                     Data_out_enable = 'b0;
                 end
             end
         ] == `BST) begin                  // BST terminate a read to current bank
             'b1) begin
                 Data_out_enable = 'b0;
             end
         end

         'b0) begin
             Dq_reg <= #tOH {data_bits{'bz}};
         end

         // Detect Read or Write command
         ] == `READ || Command[] == `READ_A) begin
             Bank = Bank_addr[];
             Col = Col_addr[];
             Col_brst = Col_addr[];
             ] == 'b00) begin
                 Row = B0_row_addr;
             ] == 'b01) begin
                 Row = B1_row_addr;
             ] == 'b10) begin
                 Row = B2_row_addr;
             ] == 'b11) begin
                 Row = B3_row_addr;
             end
             Burst_counter = ;
             Data_in_enable = 'b0;
             Data_out_enable = 'b1;
         ] == `WRITE || Command[] == `WRITE_A) begin
             Bank = Bank_addr[];
             Col = Col_addr[];
             Col_brst = Col_addr[];
             ] == 'b00) begin
                 Row = B0_row_addr;
             ] == 'b01) begin
                 Row = B1_row_addr;
             ] == 'b10) begin
                 Row = B2_row_addr;
             ] == 'b11) begin
                 Row = B3_row_addr;
             end
             Burst_counter = ;
             Data_in_enable = 'b1;
             Data_out_enable = 'b0;
         end

         // DQ buffer (Driver/Receiver)
         'b1) begin                                   // Writing Data to Memory
             // Array buffer
             'b00) Dq_dqm [data_bits - 1  : 0] = Bank0 [{Row, Col}];
             'b01) Dq_dqm [data_bits - 1  : 0] = Bank1 [{Row, Col}];
             'b10) Dq_dqm [data_bits - 1  : 0] = Bank2 [{Row, Col}];
             'b11) Dq_dqm [data_bits - 1  : 0] = Bank3 [{Row, Col}];
             // Dqm operation
             ] == 'b0) Dq_dqm [ 7 : 0] = Dq [ 7 : 0];
             ] == 'b0) Dq_dqm [15 : 8] = Dq [15 : 8];
             //if (Dqm[2] == 1'b0) Dq_dqm [23 : 16] = Dq [23 : 16];
            // if (Dqm[3] == 1'b0) Dq_dqm [31 : 24] = Dq [31 : 24];
             // Write to memory
             'b00) Bank0 [{Row, Col}] = Dq_dqm [data_bits - 1  : 0];
             'b01) Bank1 [{Row, Col}] = Dq_dqm [data_bits - 1  : 0];
             'b10) Bank2 [{Row, Col}] = Dq_dqm [data_bits - 1  : 0];
             'b11) Bank3 [{Row, Col}] = Dq_dqm [data_bits - 1  : 0];
             :]=='h4)
                 $display("at time %t WRITE: Bank = %d Row = %d, Col = %d, Data = Hi-Z due to DQM", $time, Bank, Row, Col);
             //$fdisplay(test_file,"bank:%h    row:%h    col:%h    write:%h",Bank,Row,Col,Dq_dqm);
             // Output result
             'b1111) begin
                 if (Debug) $display("at time %t WRITE: Bank = %d Row = %d, Col = %d, Data = Hi-Z due to DQM", $time, Bank, Row, Col);
             end else begin
                 if (Debug) $display("at time %t WRITE: Bank = %d Row = %d, Col = %d, Data = %d, Dqm = %b", $time, Bank, Row, Col, Dq_dqm, Dqm);
                 // Record tWR time and reset counter
                 WR_chk [Bank] = $time;
                 WR_counter [Bank] = ;
             end
             // Advance burst counter subroutine
             #tHZ Burst;
         'b1) begin                         // Reading Data from Memory
             //$display("%h    ,    %h,    %h",Bank0,Row,Col);
             // Array buffer
             'b00) Dq_dqm [data_bits - 1  : 0] = Bank0 [{Row, Col}];
             'b01) Dq_dqm [data_bits - 1  : 0] = Bank1 [{Row, Col}];
             'b10) Dq_dqm [data_bits - 1  : 0] = Bank2 [{Row, Col}];
             'b11) Dq_dqm [data_bits - 1  : 0] = Bank3 [{Row, Col}];

             // Dqm operation
             ] == 'b1) Dq_dqm [ 7 : 0] = 8'bz;
             ] == 'b1) Dq_dqm [15 : 8] = 8'bz;
             ] == 'b1) Dq_dqm [23 : 16] = 8'bz;
             ] == 'b1) Dq_dqm [31 : 24] = 8'bz;
             // Display result
             Dq_reg [data_bits -   : ] = #tAC Dq_dqm [data_bits -   : ];
             'b1111) begin
                 if (Debug) $display("at time %t READ : Bank = %d Row = %d, Col = %d, Data = Hi-Z due to DQM", $time, Bank, Row, Col);
             end else begin
                 if (Debug) $display("at time %t READ : Bank = %d Row = %d, Col = %d, Data = %d, Dqm = %b", $time, Bank, Row, Col, Dq_reg, Dqm_reg0);
             end
             // Advance burst counter subroutine
             Burst;
         end
     end

     //  Write with Auto Precharge Calculation
     //      The device start internal precharge:
     //          1.  tWR Clock after last burst
     //      and 2.  Meet minimum tRAS requirement
     //       or 3.  Interrupt by a Read or Write (with or without AutoPrecharge)
     ]) begin
         ] == 'b1) && (Write_precharge[0] == 1'b1)) begin
             if ((($time - RAS_chk0 >= tRAS) &&                                                          // Case 2
                (((Burst_length_1 == ] >= ) ||   // Case 1
                  (Burst_length_2 == 'b1 && Count_precharge [0] >= 2) ||
                  (Burst_length_4 == 'b1 && Count_precharge [0] >= 4) ||
                  (Burst_length_8 == 'b1 && Count_precharge [0] >= 8))) ||
                  (RW_interrupt_write[] == 'b1 && WR_counter[0] >= 2)) begin                           // Case 3 (stop count when interrupt)
                     Auto_precharge[] = 'b0;
                     Write_precharge[] = 'b0;
                     RW_interrupt_write[] = 'b0;
                     #tWRa;                          // Wait for tWR
                     Pc_b0 = 'b1;
                     Act_b0 = 'b0;
                     RP_chk0 = $time;
                     if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 0", $time);
             end
         end
     end
     ]) begin
         ] == 'b1) && (Write_precharge[1] == 1'b1)) begin
             if ((($time - RAS_chk1 >= tRAS) &&
                (((Burst_length_1 == ] >= ) ||
                  (Burst_length_2 == 'b1 && Count_precharge [1] >= 2) ||
                  (Burst_length_4 == 'b1 && Count_precharge [1] >= 4) ||
                  (Burst_length_8 == 'b1 && Count_precharge [1] >= 8))) ||
                  (RW_interrupt_write[] == 'b1 && WR_counter[1] >= 2)) begin
                     Auto_precharge[] = 'b0;
                     Write_precharge[] = 'b0;
                     RW_interrupt_write[] = 'b0;
                     #tWRa;                          // Wait for tWR
                     Pc_b1 = 'b1;
                     Act_b1 = 'b0;
                     RP_chk1 = $time;
                     if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 1", $time);
             end
         end
     end
     ]) begin
         ] == 'b1) && (Write_precharge[2] == 1'b1)) begin
             if ((($time - RAS_chk2 >= tRAS) &&
                (((Burst_length_1 == ] >= ) ||
                  (Burst_length_2 == 'b1 && Count_precharge [2] >= 2) ||
                  (Burst_length_4 == 'b1 && Count_precharge [2] >= 4) ||
                  (Burst_length_8 == 'b1 && Count_precharge [2] >= 8))) ||
                  (RW_interrupt_write[] == 'b1 && WR_counter[2] >= 2)) begin
                     Auto_precharge[] = 'b0;
                     Write_precharge[] = 'b0;
                     RW_interrupt_write[] = 'b0;
                     #tWRa;                          // Wait for tWR
                     Pc_b2 = 'b1;
                     Act_b2 = 'b0;
                     RP_chk2 = $time;
                     if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 2", $time);
             end
         end
     end
     ]) begin
         ] == 'b1) && (Write_precharge[3] == 1'b1)) begin
             if ((($time - RAS_chk3 >= tRAS) &&
                (((Burst_length_1 == ] >= ) ||
                  (Burst_length_2 == 'b1 && Count_precharge [3] >= 2) ||
                  (Burst_length_4 == 'b1 && Count_precharge [3] >= 4) ||
                  (Burst_length_8 == 'b1 && Count_precharge [3] >= 8))) ||
                  (RW_interrupt_write[] == 'b1 && WR_counter[3] >= 2)) begin
                     Auto_precharge[] = 'b0;
                     Write_precharge[] = 'b0;
                     RW_interrupt_write[] = 'b0;
                     #tWRa;                          // Wait for tWR
                     Pc_b3 = 'b1;
                     Act_b3 = 'b0;
                     RP_chk3 = $time;
                     if (Debug) $display ("at time %t NOTE : Start Internal Auto Precharge for Bank 3", $time);
             end
         end
     end

     task Burst;
         begin
             // Advance Burst Counter
             Burst_counter = Burst_counter + ;

             // Burst Type
             ] == 'b0) begin                                  // Sequential Burst
                 Col_temp = Col + ;
             ] == 'b1) begin                         // Interleaved Burst
                 Col_temp[] =  Burst_counter[] ^  Col_brst[];
                 Col_temp[] =  Burst_counter[] ^  Col_brst[];
                 Col_temp[] =  Burst_counter[] ^  Col_brst[];
             end

             // Burst Length
             if (Burst_length_2) begin                                       // Burst Length = 2
                 Col [] = Col_temp [];
             end else if (Burst_length_4) begin                              // Burst Length = 4
                 Col [ : ] = Col_temp [ : ];
             end else if (Burst_length_8) begin                              // Burst Length = 8
                 Col [ : ] = Col_temp [ : ];
             end else begin                                                  // Burst Length = FULL
                 Col = Col_temp;
             end

             // Burst Read Single Write
             'b1) begin
                 Data_in_enable = 'b0;
             end

             // Data Counter
             'b1) begin
                 ) begin
                     Data_in_enable = 'b0;
                     Data_out_enable = 'b0;
                 end
             'b1) begin
                 ) begin
                     Data_in_enable = 'b0;
                     Data_out_enable = 'b0;
                 end
             'b1) begin
                 ) begin
                     Data_in_enable = 'b0;
                     Data_out_enable = 'b0;
                 end
             'b1) begin
                 ) begin
                     Data_in_enable = 'b0;
                     Data_out_enable = 'b0;
                 end
             end
         end
     endtask

     //**********************将SDRAM内的数据直接输出到外部文件*******************************//

 /*
    integer    sdram_data,ind;

     always@(sdram_r)
     begin
            sdram_data=$fopen("sdram_data.txt");
            $display("Sdram dampout begin ",sdram_data);
 //           $fdisplay(sdram_data,"Bank0:");
            for(ind=0;ind<=mem_sizes;ind=ind+1)
                     $fdisplay(sdram_data,"%h    %b",ind,Bank0[ind]);
 //           $fdisplay(sdram_data,"Bank1:");
            for(ind=0;ind<=mem_sizes;ind=ind+1)
                     $fdisplay(sdram_data,"%h    %b",ind,Bank1[ind]);
 //           $fdisplay(sdram_data,"Bank2:");
            for(ind=0;ind<=mem_sizes;ind=ind+1)
                     $fdisplay(sdram_data,"%h    %b",ind,Bank2[ind]);
 //               $fdisplay(sdram_data,"Bank3:");
            for(ind=0;ind<=mem_sizes;ind=ind+1)
                     $fdisplay(sdram_data,"%h    %b",ind,Bank3[ind]);

           $fclose("sdram_data.txt");
       //->compare;
       end
 */
     integer    sdram_data,sdram_mem;
     :]    aa,cc;
     :]    bb,ee;

     always@(sdram_r)
     begin
            $display("Sdram dampout begin ",$realtime);
            sdram_data=$fopen("sdram_data.txt");
            ;aa<*(mem_sizes+);aa=aa+)
                begin
                bb=aa[:];
             if(aa<=mem_sizes)
                 $fdisplay(sdram_data,"%0d    %0h",aa,Bank0[bb]);
             *mem_sizes+)
                         $fdisplay(sdram_data,"%0d    %0h",aa,Bank1[bb]);
             *mem_sizes+)
                 $fdisplay(sdram_data,"%0d    %0h",aa,Bank2[bb]);
             else
                 $fdisplay(sdram_data,"%0d    %0h",aa,Bank3[bb]);
               end
           $fclose("sdram_data.txt");

           sdram_mem=$fopen("sdram_mem.txt");
           ;cc<*(mem_sizes+);cc=cc+)
               begin
                ee=cc[:];
             if(cc<=mem_sizes)
                 $fdisplay(sdram_mem,"%0h",Bank0[ee]);
             *mem_sizes+)
                         $fdisplay(sdram_mem,"%0h",Bank1[ee]);
             *mem_sizes+)
                 $fdisplay(sdram_mem,"%0h",Bank2[ee]);
             else
                 $fdisplay(sdram_mem,"%0h",Bank3[ee]);
               end
           $fclose("sdram_mem.txt");

       end

 //    // Timing Parameters for -75 (PC133) and CAS Latency = 2
 //    specify
 //        specparam
 ////                    tAH  =  0.8,                                        // Addr, Ba Hold Time
 ////                    tAS  =  1.5,                                        // Addr, Ba Setup Time
 ////                    tCH  =  2.5,                                        // Clock High-Level Width
 ////                    tCL  =  2.5,                                        // Clock Low-Level Width
 //////                    tCK  = 10.0,                                       // Clock Cycle Time  100mhz
 //////                    tCK  = 7.5,                        // Clock Cycle Time  133mhz
 ////                    tCK  =  7,                                // Clock Cycle Time  143mhz
 ////                    tDH  =  0.8,                                        // Data-in Hold Time
 ////                    tDS  =  1.5,                                        // Data-in Setup Time
 ////                    tCKH =  0.8,                                        // CKE Hold  Time
 ////                    tCKS =  1.5,                                        // CKE Setup Time
 ////                    tCMH =  0.8,                                        // CS#, RAS#, CAS#, WE#, DQM# Hold  Time
 ////                    tCMS =  1.5;                                        // CS#, RAS#, CAS#, WE#, DQM# Setup Time
 //                    tAH  =  1,                                        // Addr, Ba Hold Time
 //                    tAS  =  1.5,                                        // Addr, Ba Setup Time
 //                    tCH  =  1,                                        // Clock High-Level Width
 //                    tCL  =  3,                                        // Clock Low-Level Width
 ////                    tCK  = 10.0,                                       // Clock Cycle Time  100mhz
 ////                    tCK  = 7.5,                        // Clock Cycle Time  133mhz
 //                    tCK  =  7,                                // Clock Cycle Time  143mhz
 //                    tDH  =  1,                                        // Data-in Hold Time
 //                    tDS  =  2,                                        // Data-in Setup Time
 //                    tCKH =  1,                                        // CKE Hold  Time
 //                    tCKS =  2,                                        // CKE Setup Time
 //                    tCMH =  0.8,                                        // CS#, RAS#, CAS#, WE#, DQM# Hold  Time
 //                    tCMS =  1.5;                                        // CS#, RAS#, CAS#, WE#, DQM# Setup Time
 //        $width    (posedge Clk,           tCH);
 //        $width    (negedge Clk,           tCL);
 //        $period   (negedge Clk,           tCK);
 //        $period   (posedge Clk,           tCK);
 //        $setuphold(posedge Clk,    Cke,   tCKS, tCKH);
 //        $setuphold(posedge Clk,    Cs_n,  tCMS, tCMH);
 //        $setuphold(posedge Clk,    Cas_n, tCMS, tCMH);
 //        $setuphold(posedge Clk,    Ras_n, tCMS, tCMH);
 //        $setuphold(posedge Clk,    We_n,  tCMS, tCMH);
 //        $setuphold(posedge Clk,    Addr,  tAS,  tAH);
 //        $setuphold(posedge Clk,    Ba,    tAS,  tAH);
 //        $setuphold(posedge Clk,    Dqm,   tCMS, tCMH);
 //        $setuphold(posedge Dq_chk, Dq,    tDS,  tDH);
 //    endspecify

 endmodule

sdram_model_plus

7.最后附上仿真结果

打印信息,简单明了,这是我喜欢的风格

基于fpga的256m的SDRAM控制器-LMLPHP

再来看看波形吧

基于fpga的256m的SDRAM控制器-LMLPHP

完美,忙活了一天有些坑真的自己填,因为每填完一个坑,起身更强大,明天继续

2018/730

今天继续更新,有很多事耽搁了两天

二.仲裁机制和刷新操作

1.刷新操作是sdram必须的操作,使用不当数据指定丢失,具体为什么自己去查一下,我省的废话了。

既然是刷新,那么就应该有刷新的周期,这个怎么计算呢,打开datasheet,看图。红框意思是64ms内要进行8192次刷新,那么刷新周期大约7.8us

基于fpga的256m的SDRAM控制器-LMLPHP

2.该刷新时序以及命令了

看下面的时序图等初始化完成后,刷新操作的第一步就是预充电(precharge),然后等tRP时间进行auto refresh(自刷新),后面再一次刷新和active都不用进行。前面哪个时间自己对应手册查一下,一般不会有错

这儿提一下,在预充电的时候,地址引脚要同时进行操作,A0~A9、A11、A12不用管,只对A10进行操作,如果A10位1,就是对所有bank进行充电,为0时选择bank进行充电,我们是为1。

基于fpga的256m的SDRAM控制器-LMLPHP

3.刷新就说完了,该附上源代码了

 module sdram_aref(
         //system signals
         input                    sclk            ,
         input                    s_rst_n            ,
         //comunicat with ARBIT
         input                    ref_en            ,
         output    wire            ref_req            ,
         output    wire            flag_ref_end    ,
         //others
         :]    aref_cmd        ,
         :]    sdram_addr        ,
         input                    flag_init_end
 );

 //==============================================================================\
 //*********************Define Parameter and Internal Signal ********************
 //==============================================================================/
         ;
 'b0001    ;
 'b0111    ;
 'b0010    ;
 :]            cmd_cnt                    ;
 :]            ref_cnt                    ;
 reg                        flag_ref                ;

 //=============================================================================\
 //********************** Main Code    ***************************************
 //=============================================================================/
 always @(posedge sclk or negedge s_rst_n) begin
         'b0)
                 ref_cnt <= 'd0;
         else if(ref_cnt >= DELAY_78us)
                 ref_cnt <= 'd0;
         'b1)
                 ref_cnt <= ref_cnt +'b1;
 end

 always @(posedge sclk or negedge s_rst_n) begin
         'b0)
                 flag_ref <= 'b0;
         'b1)
                 flag_ref <=    'b0;
         'b1)
                 flag_ref <= 'b1;
 end

 always @(posedge sclk or negedge s_rst_n ) begin
         'b0)
                 cmd_cnt    <= 'd0;
         'b1)
                 cmd_cnt <= cmd_cnt + 'b1;
         else
                 cmd_cnt <= 'd0;
 end

 always @(posedge sclk or negedge s_rst_n) begin
         'b0)
                 aref_cmd <= CMD_NOP;
         else case(cmd_cnt)
                 :        aref_cmd <= CMD_PRE;
                 :        aref_cmd <= CMD_AREF;
                 default:aref_cmd <= CMD_NOP;
         endcase
 end

 'b0;
 'd0_0100_0000_0000;
 'b1 : 1'b0;

 endmodule

sdram_aref

4.仲裁机制

为什么要这个仲裁机制,sdram工作是有刷新、写和读3个操作,我们需要这个仲裁机制来协调这三个操作,引用邓堪文老师一个图,大家一看就应该很明白了

基于fpga的256m的SDRAM控制器-LMLPHP

5.具体的操作在sdram_top模块里,附上源码自己研究一下,这只写了三种状态,其他状态后面学习了在更新

 module sdram_top(
         //system signals
         input                    sclk            ,
         input                    s_rst_n            ,
         //SDRAM Interfaces
         output    wire            sdram_clk        ,
         output    wire            sdram_cke        ,
         output    wire            sdram_cs_n        ,
         output    wire            sdram_cas_n        ,
         output    wire            sdram_ras_n        ,
         output    wire            sdram_we_n        ,
         :]    sdram_bank        ,
         :]    sdram_addr        ,
         :]    sdram_dqm        ,
         :]    sdram_dq
 );

 //==============================================================================\
 //*********************Define Parameter and Internal Signal ********************
 //==============================================================================/
 'b0_0001        ;
 'b0_0010        ;
 'b0_0100        ;

 //init module
 wire                    flag_init_end            ;
 :]            init_cmd                ;
 :]            init_addr                ;
 //
 :]            state                    ;
 //refresh module
 wire                    ref_req                    ;
 wire                    flag_ref_end            ;
 reg                        ref_en                    ;
 :]            ref_cmd                    ;
 :]            ref_addr                ;

 //=============================================================================\
 //********************** Main Code    ***************************************
 //=============================================================================/
 always @(posedge sclk or negedge s_rst_n) begin
         'b0)
                 state    <=    IDLE;

         else case(state)
                 IDLE:
                         'b1)
                             state <= ARBIT;
                         else
                             state <= IDLE;
                 ARBIT:
                         'b1)
                             state <= AREF;
                         else
                             state <= ARBIT;
                 AREF:
                         'b1)
                             state <= ARBIT;
                         else
                             state    <=AREF;
                 default:
                             state <= IDLE;
         endcase
 end

 //ref_en
 always @(posedge sclk or negedge s_rst_n) begin
         'b0)
                 ref_en <= 'b0;
         'b1)
                 ref_en <= 'b1;
             else
                 ref_en <= 'b0;
 end

 'b1;
 assign    sdram_addr        =    (state == IDLE)    ?    init_addr    :    ref_addr;
 assign    {sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n}    =    (state == IDLE)    ?    init_cmd    :    ref_cmd;
 'd0;
 assign    sdram_clk         =     ~sclk;

 sdram_ini        sdram_ini_inst(
         //systejm sign
         .sclk                    (sclk            ),
         .s_rst_n                (s_rst_n        ),
         //others
         .cmd_reg                (init_cmd        ),
         .sdram_addr                (init_addr        ),
         .flag_init_end           (flag_init_end    )
 );

 sdram_aref        sdram_aref_inst(
         //system signals
         .sclk                    (sclk            ),
         .s_rst_n                (s_rst_n        ),
         //comunicat with ARBIT
         .ref_en                    (ref_en            ),
         .ref_req                (ref_req        ),
         .flag_ref_end            (flag_ref_end    ),
         //others
         .aref_cmd                (ref_cmd        ),
         .sdram_addr                (ref_addr        ),
         .flag_init_end            (flag_init_end    )
 );

 endmodule

sdram_top

6.最后老规矩放上仿真结果以及仿真波形图

初始化没有错,刷星也一直进行,没有错误

基于fpga的256m的SDRAM控制器-LMLPHP

在看看波形图,没次看到这些信号就觉得自己就是个大牛,哈哈哈! 自恋了,但是还是个入了门的菜鸡。看图信号和数据都没问题,完美!

基于fpga的256m的SDRAM控制器-LMLPHP

2018.9.14

首先骂一下狗逼学校都要写完了停电了。我靠全没了,暑假就停了我那么久的网,还到处开挖,挖金子啊绝地三尺关键是堵道。无语了。。。

消气还是重写吧,一个多月了,打算每做好一个功能就更的,可惜就该这个狗逼学校事多还停水停网,但是我也没停下。现在补上吧,下午都快写完了突然停电主机关机了,呵呵,现在就这样了

首先看一下现在做好的图片显示系统,用串口发送640*480的图片给FPGA,波特率是1562500,最快的了,VGA驱动显示屏。

说实话我不想再从写了,很烦,还有很多事要忙,真心要学的可以私聊我!

基于fpga的256m的SDRAM控制器-LMLPHP

基于fpga的256m的SDRAM控制器-LMLPHP

05-08 08:28