• 【黑金原创教程】【FPGA那些事儿-驱动篇I 】实验二十:SDRAM模块③ — 页读写 α


    实验二十:SDRAM模块③ — 页读写 α

    完成单字读写与多字读写以后,接下来我们要实验页读写。丑话当前,实验二十的页读写只是实验性质的东西,其中不存在任何实用价值,笔者希望读者可以把它当成页读写的热身运动。

    表示20.1 Mode Register的内容。

    Mode Register

    A12

    A11

    A10

    A9

    A8

    A7

    A6

    A5

    A4

    A3

    A2

    A1

    A0

    0

    0

    OP Code

    0

    0

    CAS Latency

    BT

    Burst Length

    A3

    Burst Type

    0

    Sequential

    1

    Interleave

     

    Burst Length

    A2

    A1

    A0

    A3 = 0

    A3 = 1

    0

    0

    0

    1

    1

    0

    0

    1

    2

    2

    0

    1

    0

    4

    4

    0

    1

    1

    8

    8

    1

    1

    1

    Full Page

    Reserved

    A9

    Write Mode

    0

    Burst Read and Burst Write

    1

    Burst Read and Single Write

    A6

    A5

    A4

    CAS Latency

    0

    1

    0

    2

    0

    1

    1

    3

    所谓页读写就是全列读写,而且表20.1告诉我们,页读写必须将 A2~A0设置为3’b111。然而,Verilog的描述结果如代码20.1所示:

     7: // Send LMR Cmd. Burst Read & Write,  3'b010 mean CAS latecy = 3, Sequential,Full Page
     begin rCMD <= _LMR; rBA <= 2'b11; rA <= { 3'd0, 1'b0, 2'd0, 3'b011, 1'b0, 3'b111 }; i <= i + 1'b1; end

    代码20.1

    如果我们一页一页的叫,基本上“一页”的定义是非常暧昧的,因为“一页”所指定的范围会随着该存储器的容量而有所改变。举例HY57V2562GTR 这只SDRAM,地址的指定范围有 BA1~BA0,R12~R0,C8~C0,其中“一页”是全列,亦即C8~C0。根据计算,C8~C0等价29 = 512,或者说页读写有512的地址偏移量。

    页写操作:

    clip_image002

    图20.1 页写操作的理想时序图。

    图20.1是笔者自定义的页写操作的理想时序图,其中C1是为了控制读写的次数。页读写相较字读写,前者好比一只不会停下冲锋的山猪。一旦读写开始,SDRAM内部的计数器就会从0开始计数,计数结果为511又会从0重新计数。因为如此,页读写需要利用BSTP命令禁止山猪继续冲锋。

    此外,自动预充对页读写来说是无效的东西,因此A10拉不拉高都没有关系,而且页写操作也不需要满足 TWR/TDPL与TPR。图20.1大致的时序过程如下:

    l T1,发送ACT命令,BANK地址与行地址;

    l T1半周期,SDRAM读取;

    l T2,满足TRCD;

    l T3,发送WR命令,BANK地址与列地址,还有第0数据;

    l T3半周期,SDRAM读取

    l T4,发送第1~511数据,然后发送BSTP命令结束页写。

    Verilog则可以这样描述,结果如代码20.2所示:

    1.    1: // Send Active Command with Bank and Row address
    2.    begin rCMD <= _ACT; rBA <= iAddr[23:22]; rA <= iAddr[21:9]; i <= i + 1'b1; end
    3.                         
    4.    2: // wait TRCD 20ns
    5.    if( C1 == TRCD -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    6.    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end             
    7.                    
    8.    3: // Send Write command with row address 
    9.    begin rCMD <= _WR; rBA <= iAddr[23:22]; rA <= { 4'b0010, iAddr[8:0] }; D1 <= iData; i <= i + 1'b1; end
    10.                         
    11.     4: // continue write until end and send BSTP 
    12.     if( C1 == 512 -1 ) begin rCMD <= _BSTP; C1 <= 14'd0; i <= i + 1'b1 ;end
    13.     else begin rCMD <= _NOP; C1 <= C1 + 1'b1; D1 <= D1 + 1'b1; end 

    代码20.2

    如代码20.2所示,步骤3写第0数据,步骤4则写入第1~511数据并且发送 BSTP命令。

    页读操作:

    clip_image004

    图20.2 页读操作的理想时序图。

    图20.2也是笔者自定义的理想时序图。同样,页读操也是一只不断冲锋的山猪,因此它需要BSTP这支停下的告示牌。除此之外,页读也没有自行预充电的必要,而且TPR也不用满足。实验二十要实验的页读比较单纯,我们读取第0数据以后立即发送BSTP命令来结束也操作。图20.2大致的时序过程如下:

    l T1,发送ACT命令,BANK地址与行地址;

    l T1半周期,SDRAM读取;

    l T2,满足TRCD;

    l T3,发送RD命令,BANK地址与列地址;

    l T3半周期,SDRAM读取命令。

    l T4,满足 CAS Latency。

    l T5,读取第0数据,然后发送BSTP命令。

    Verilog则可以这样描述,结果如代码20.3所示:

    1.    1: // Send Active command with Bank and Row address
    2.    begin rCMD <= _ACT; rBA <= iAddr[23:22]; rA <= iAddr[21:9]; i <= i + 1'b1; end
    3.                         
    4.    2: // wait TRCD 20ns
    5.    if( C1 == TRCD -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    6.    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end 
    7.                    
    8.    3: // Send Read command and column address
    9.    begin rCMD <= _RD; rBA <= iAddr[23:22]; rA <= { 4'b0010, iAddr[8:0]}; i <= i + 1'b1; end
    10.    
    11.    4: // wait CL 3 clock
    12.    if( C1 == CL -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    13.    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end 
    14.                    
    15.    5: // Read Data
    16.    begin D1 <= S_DQ; rCMD <= _BSTP; i <= i + 1'b1; end

    代码20.3

    如代码20.3所示,步骤5读取数据以后立即发送 BSTP命令以示结束页读操作。理解完毕以后我们便可以开始建模了。

    clip_image006

    图20.3 SDRAM基础模块的建模图。

    图20.3是SDRAM基础模块的建模图,外表上和实验十八差不多,不过SDRAM功能模块的内容却有一些改变。

    sdram_funcmod.v
    1.    module sdram_funcmod
    2.    (
    3.         input CLOCK,
    4.         input RESET,
    5.         
    6.         output S_CKE, S_NCS, S_NRAS, S_NCAS, S_NWE,
    7.         output [1:0]S_BA,  
    8.         output [12:0]S_A,  
    9.         output [1:0]S_DQM,
    10.         inout [15:0]S_DQ,
    11.         
    12.         input [3:0]iCall,
    13.         output oDone,
    14.         input [23:0]iAddr,  // [23:22]BA,[21:9]Row,[8:0]Column
    15.         input [15:0]iData,
    16.         output [15:0]oData
    17.    );

    第3~16行是相关的输入端声明。

    18.        parameter T100US = 14'd13300;
    19.        // tRP 20ns, tRRC 63ns, tRCD 20ns, tMRD 2CLK, tWR/tDPL 2CLK, CAS Latency 3CLK
    20.        parameter TRP = 14'd3, TRRC = 14'd9, TMRD = 14'd2, TRCD = 14'd3, TWR = 14'd2, CL = 14'd3;
    21.        parameter _INIT = 5'b01111, _NOP = 5'b10111, _ACT = 5'b10011, _RD = 5'b10101, _WR = 5'b10100,
    22.                _BSTP = 5'b10110, _PR = 5'b10010, _AR = 5'b10001, _LMR = 5'b10000;
    23.         

    第18~22行是相关的常量声明。

    24.        reg [4:0]i;
    25.        reg [13:0]C1;
    26.        reg [15:0]D1;
    27.        reg [4:0]rCMD;
    28.        reg [1:0]rBA;
    29.        reg [12:0]rA;
    30.        reg [1:0]rDQM;
    31.        reg isOut;
    32.        reg isDone;
    33.    
    34.        always @ ( posedge CLOCK or negedge RESET )
    35.            if( !RESET )
    36.                begin
    37.                    i <= 4'd0;
    38.                   C1 <= 14'd0;
    39.                   D1 <= 16'd0;
    40.                    rCMD <= _NOP;
    41.                    rBA <= 2'b11;
    42.                    rA <= 13'h1fff;
    43.                    rDQM <= 2'b00;
    44.                    isOut <= 1'b1;
    45.                   isDone <= 1'b0;
    46.                end

    第24~46行是相关的寄存器声明与复位操作。

    47.              else if( iCall[3] )
    48.                case( i )
    49.                    
    50.                    0: // Set IO to output State
    51.                    begin isOut <= 1'b1; i <= i + 1'b1; end
    52.                       
    53.                    1: // Send Active Command with Bank and Row address
    54.                    begin rCMD <= _ACT; rBA <= iAddr[23:22]; rA <= iAddr[21:9]; i <= i + 1'b1; end
    55.                         
    56.                   2: // wait TRCD 20ns
    57.                   if( C1 == TRCD -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    58.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end             
    59.                    
    60.                    /*********************************************/
    61.                    
    62.                    3: // Send Write command with row address
    63.                    begin rCMD <= _WR; rBA <= iAddr[23:22]; rA <= { 4'b0010, iAddr[8:0] }; D1 <= iData; i <= i + 1'b1; end
    64.                         
    65.                    4: // continue write until end and send BSTP 
    66.                   if( C1 == 512 -1 ) begin rCMD <= _BSTP; C1 <= 14'd0; i <= i + 1'b1 ;end
    67.                   else begin rCMD <= _NOP; C1 <= C1 + 1'b1; D1 <= D1 + 1'b1; end 
    68.                     
    69.                    /**********************************************/
    70.                         
    71.                    5: // Generate done signal
    72.                    begin rCMD <= _NOP; isDone <= 1'b1; i <= i + 1'b1; end
    73.                        
    74.                   6:
    75.                   begin isDone <= 1'b0; i <= 4'd0; end
    76.                    
    77.                endcase

    以上内容为页写操作,注意步骤3写入第0数据,步骤4则写入第1~511数据并且发送BSTP命令。

     
    78.            else if( iCall[2] )
    79.                case( i )
    80.                    
    81.                    0:
    82.                    begin isOut <= 1'b0; D1 <= 16'd0; i <= i + 1'b1; end
    83.    
    84.                    1: // Send Active command with Bank and Row address
    85.                    begin rCMD <= _ACT; rBA <= iAddr[23:22]; rA <= iAddr[21:9]; i <= i + 1'b1; end
    86.                         
    87.                    2: // wait TRCD 20ns
    88.                    if( C1 == TRCD -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    89.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end 
    90.                
    91.                    /********************/
    92.                    
    93.                    3: // Send Read command and column address
    94.                    begin rCMD <= _RD; rBA <= iAddr[23:22]; rA <= { 4'b0010, iAddr[8:0]}; i <= i + 1'b1; end
    95.    
    96.                    4: // wait CL 3 clock
    97.                    if( C1 == CL -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    98.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end 
    99.                                       
    100.                    /********************/ 
    101.                    
    102.                    5: // Read Data
    103.                    begin D1 <= S_DQ; rCMD <= _BSTP; i <= i + 1'b1; end
    104.                    
    105.                    /********************/
    106.                
    107.                    6: // Generate done signal
    108.                    begin rCMD <= _NOP; isDone <= 1'b1; i <= i + 1'b1; end
    109.                        
    110.                    7:
    111.                    begin isDone <= 1'b0; i <= 4'd0; end
    112.    
    113.                endcase

    以上内容为页读操作,注意步骤5是读取第0数据并且发送 BSTP命令。

    114.              else if( iCall[1] )
    115.                case( i )
    116.                    
    117.                    0: // Send Precharge Command
    118.                    begin rCMD <= _PR; i <= i + 1'b1; end
    119.                         
    120.                    1: // wait TRP 20ns
    121.                    if( C1 == TRP -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    122.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
    123.                         
    124.                    2: // Send Auto Refresh Command
    125.                    begin rCMD <= _AR; i <= i + 1'b1; end
    126.                   
    127.                    3: // wait TRRC 63ns
    128.                   if( C1 == TRRC -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    129.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
    130.                         
    131.                   4: // Send Auto Refresh Command
    132.                    begin rCMD <= _AR; i <= i + 1'b1; end
    133.                   
    134.                    5: // wait TRRC 63ns
    135.                    if( C1 == TRRC -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    136.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
    137.                    
    138.                    /********************/
    139.                    
    140.                    6: // Generate done signal
    141.                    begin isDone <= 1'b1; i <= i + 1'b1; end
    142.                        
    143.                   7:
    144.                   begin isDone <= 1'b0; i <= 4'd0; end
    145.    
    146.                endcase

    以上内容是刷新操作。

     
    147.              else if( iCall[0] )
    148.                case( i )
    149.                    
    150.                   0:  // delay 100us
    151.                   if( C1 == T100US -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    152.                   else begin C1 <= C1 + 1'b1; end 
    153.                   
    154.                   /********************/
    155.                   
    156.                   1: // Send Precharge Command
    157.                   begin rCMD <= _PR; { rBA, rA } <= 15'h3fff; i <= i + 1'b1; end
    158.                        
    159.                   2: // wait TRP 20ns
    160.                  if( C1 == TRP -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    161.                   else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
    162.                   
    163.                   3: // Send Auto Refresh Command
    164.                   begin rCMD <= _AR; i <= i + 1'b1; end
    165.                   
    166.                   4: // wait TRRC 63ns
    167.                  if( C1 == TRRC -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    168.                   else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
    169.                        
    170.                   5: // Send Auto Refresh Command
    171.                   begin rCMD <= _AR; i <= i + 1'b1; end
    172.                   
    173.                   6: // wait TRRC 63ns
    174.                  if( C1 == TRRC -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    175.                   else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
    176.                
    177.                   /********************/
    178.                   
    179.                   7: // Send LMR Cmd. Burst Read & Write,  3'b010 mean CAS latecy = 3, Sequential,Full Page
    180.                   begin rCMD <= _LMR; rBA <= 2'b11; rA <= { 3'd0, 1'b0, 2'd0, 3'b011, 1'b0, 3'b111 }; i <= i + 1'b1; end
    181.                        
    182.                   8: // Send 2 nop CLK for tMRD
    183.                   if( C1 == TMRD -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    184.                   else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
    185.                   
    186.                   /********************/
    187.                   
    188.                   9: // Generate done signal
    189.                   begin isDone <= 1'b1; i <= i + 1'b1; end
    190.                        
    191.                   10:
    192.                   begin isDone <= 1'b0; i <= 4'd0; end
    193.                   
    194.                endcase
    195.      

    以上内容是初始化,注意步骤7的Mode Register 内容,Busrt Length 为 3’b111。

    196.         assign { S_CKE, S_NCS, S_NRAS, S_NCAS, S_NWE } = rCMD;
    197.         assign { S_BA, S_A } = { rBA, rA };
    198.         assign S_DQM = rDQM;
    199.         assign S_DQ  = isOut ? D1 : 16'hzzzz;
    200.         assign oDone = isDone;
    201.         assign oData = D1;
    202.    
    203.    endmodule

    第196~201行是相关的输出驱动。

    sdram_ctrlmod.v

    该控制模块的内容与实验十八一致。

    sdram_basemod.v

    该组合模块的内容也与实验十八一致

    sdram_demo.v

    clip_image008

    图20.4 实验二十的建模图。

    图20.4是实验二十的建模图,外观上与实验十八一样,不过核心操作的内容却有所不同,具体内容我们还是来看代码吧。

    1.    module sdram_demo
    2.    (
    3.        input CLOCK,
    4.        input RESET,
    5.        output S_CLK,
    6.        output S_CKE, S_NCS, S_NRAS, S_NCAS, S_NWE,
    7.        output [12:0]S_A, 
    8.        output [1:0]S_BA,
    9.        output [1:0]S_DQM,
    10.        inout [15:0]S_DQ,
    11.        output TXD
    12.    ); 

    以上内容为相关的出入端声明。

    13.         wire CLOCK1,CLOCK2;
    14.         
    15.         pll_module U1
    16.         (
    17.                .inclk0 ( CLOCK ), // 50Mhz
    18.                .c0 ( CLOCK1 ),  // 133Mhz -210 degree phase
    19.                .c1 ( CLOCK2 )   // 133Mhz 
    20.         );
    21.         

    以上内容为PLL模块的实例化。

    22.         wire [1:0]DoneU2;
    23.         wire [15:0]DataU2;
    24.         
    25.         sdram_basemod U2
    26.         (
    27.              .CLOCK( CLOCK1 ),
    28.              .RESET( RESET ),
    29.              .S_CKE( S_CKE ),
    30.              .S_NCS( S_NCS ),
    31.              .S_NRAS( S_NRAS ),
    32.              .S_NCAS( S_NCAS ),
    33.              .S_NWE( S_NWE ),
    34.              .S_A( S_A ),
    35.              .S_BA( S_BA ),
    36.              .S_DQM( S_DQM ),
    37.              .S_DQ( S_DQ ),
    38.              .iCall( isCall ),
    39.              .oDone( DoneU2 ),
    40.              .iAddr( D1 ),
    41.              .iData( D2 ),
    42.              .oData( DataU2 )
    43.         );
    44.         

    以上内容为SDRAM基础模块的实例化。

    45.         parameter B115K2 = 11'd1157, TXFUNC = 6'd16;
    46.         
    47.         reg [5:0]i,Go;
    48.         reg [10:0]C1;
    49.         reg [23:0]D1;
    50.         reg [15:0]D2,D3;
    51.         reg [10:0]T;
    52.         reg [1:0]isCall;
    53.         reg rTXD;
    54.         
    55.         always @ ( posedge CLOCK1 or negedge RESET )
    56.             if( !RESET )
    57.                 begin
    58.                     i <= 6'd0;
    59.                    Go <= 6'd0;
    60.                    C1 <= 11'd0;
    61.                     D1 <= 24'd0;
    62.                    D2 <= 16'd0;
    63.                    D3 <= 16'd0;
    64.                    T <= 11'd0;
    65.                    isCall <= 2'b00;
    66.                    rTXD <= 1'b1;
    67.                 end
    68.             else 

    以上内容为相关的寄存器声明还有复位操作。第45行是波特率还有伪函数入口的常量声明。

    69.                 case( i )
    70.                        
    71.                         0:
    72.                         if( DoneU2[1] ) begin isCall[1] <= 1'b0; i <= i + 1'b1; end
    73.                         else begin isCall[1] <= 1'b1; D1 <= 24'd0; D2 <= 16'hA000; end
    74.                         
    75.                         1:
    76.                         if( DoneU2[0] ) begin D3 <= DataU2; isCall[0] <= 1'b0; i <= i + 1'b1; end
    77.                         else begin isCall[0] <= 1'b1; end
    78.                         
    79.                         2:
    80.                         begin T <= { 2'b11, D3[15:8], 1'b0 }; i <= TXFUNC; Go <= i + 1'b1; end
    81.                         
    82.                         3:
    83.                         begin T <= { 2'b11, D3[7:0], 1'b0 }; i <= TXFUNC; Go <= i + 1'b1; end
    84.                         
    85.                         4:
    86.                         if( D1 == 24'd511 ) i <= i + 1'b1;
    87.                         else begin D1 <= D1 + 1'b1; i <= 6'd1; end
    88.     
    89.                          5:
    90.                          i <= i;
    91.                         
    92.                         /******************************/
    93.                     

    以上内容为部分核心操作。步骤0将数据 16’hA×××从地址0写至地址511,其中×××会经由页写而自行递增。换句话说,数据16’hA000~16’hA1FF从地址0写至地址511。

    步骤1则用来读取数据,步骤2~3将读出的数据一一发送出去。步骤4用来递增地址,从0~511,然后返回步骤1,直至人为页读结束。

    94.                          16,17,18,19,20,21,22,23,24,25,26:
    95.                         if( C1 == B115K2 -1 ) begin C1 <= 11'd0; i <= i + 1'b1; end
    96.                         else begin rTXD <= T[i - 16]; C1 <= C1 + 1'b1; end
    97.                         
    98.                         27:
    99.                         i <= Go;
    100.                         
    101.                endcase
    102.    
    103.         assign S_CLK = CLOCK2;
    104.         assign TXD = rTXD;
    105.    
    106.    endmodule

    以上内容为部分核心操作。步骤16~27是发送一帧数据的伪函数。第103~104行则是相关的输出驱动。综合完毕并且下载程序,如果串口调试软件出现数据 A000~A1FF表示实验成功。

  • 相关阅读:
    asp.net mvc简单分页实例
    aspnetpager使用介绍
    sql server 横向转丛向及FOR XML PATH使用
    js apply使用
    js call使用
    C# JavaScriptSerializer 序列化集合
    【BZOJ4103】[Thu Summer Camp 2015]异或运算 可持久化Trie树
    【BZOJ4177】Mike的农场 最小割
    【BZOJ4205】卡牌配对 最大流
    【BZOJ4358】permu kd-tree
  • 原文地址:https://www.cnblogs.com/alinx/p/4413839.html
Copyright © 2020-2023  润新知