zoukankan      html  css  js  c++  java
  • 【黑金原创教程】【FPGA那些事儿-驱动篇I 】实验十九:SDRAM模块② — 多字读写

    实验十九:SDRAM模块② — 多字读写

    表示19.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

    实验十八我们实现单字读写,实验十九则要实现多字读写。表19.1告诉我们,A2~A0控制Burst Length的长度,为了实现长度为4的字读写,A2~A0的内容设置为3’b010。

    7: // Send LMR Cmd. Burst Read & Write, 3'b011 mean CAS latecy = 3, Sequentia 4 burst length

    begin rCMD <= _LMR; rBA <= 2'b11; rA <= { 3'd0, 1'b0, 2'd0, 3'b011, 1'b0, 3'b010 }; i <= i + 1'b1; end

    代码19.2

    如代码基本上,初始化的大致过程与实验十八没有什么两样,仅有更改 Mode Register 的内容,结果如代码19.2所示。对此,写操作还有读操作因为读写字节改变,所以时序也稍微改变了一下。

    多字写操作:

    clip_image002

    图19.1 多字写操作的理想时序图。

    图19.1是多字写操作的理想时序图。T1~T3基本上没有什么改变,反之接续的T4~T6会依据Burst Length设置的长度而有所改变。由于 Burst Length 设置为 4,结果T3写第一字数据,T4写第二字数据,T5写第三字数据,T6则写第四字,然而大致的过程如下所示:

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

    l T1半周期,SDRAM读取;

    l T2,满足TRCD;

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

    l T3半周期,SDRAM读取;

    l T4,写第二字数据;

    l T4半周期,SDRAM读取;

    l T5,写第三字数据;

    l T5半周期,SDRAM读取;

    l T6,写第四字数据;

    l T6半周期,SDRAM读取;

    l T7,满足TWR;

    l T8,满足TRP。

    Verilog则可以这样描述,结果如代码19.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, pull up A10 to PR
    9.           begin rCMD <= _WR; rBA <= iAddr[23:22]; rA <= {4'b0010,iAddr[8:0]}; D1 <= iData[63:48]; i <= i + 1'b1; end
    10.                         
    11.          4:  
    12.         begin rCMD <= _NOP; D1 <= iData[47:32]; i <= i + 1'b1; end
    13.                         
    14.         5:
    15.          begin rCMD <= _NOP; D1 <= iData[31:16]; i <= i + 1'b1; end
    16.                         
    17.         6:
    18.         begin rCMD <= _NOP; D1 <= iData[15:0]; i <= i + 1'b1; end
    19.                                          
    20.         7: // wait TWR 2 clock
    21.         if( C1 == TWR -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    22.          else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end  
    23.                         
    24.          8: // wait TRP 20ns
    25.         if( C1 == TRP -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    26.          else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end  

    代码19.2

    假设多字读写由高至低,那么步骤3写入iData[63:48],步骤4写入 iData[47:32],步骤5写入 iData[31:16],步骤6写 iData[15:0]。

    多字读操作:

    clip_image004

    图19.2 多字读操作的理想时序图。

    图19.2是多字读操作的理想时序图,大致过程如下:

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

    l T1半周期,SDRAM读取;

    l T2,满足TRCD;

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

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

    l T4,满足 CAS Latency;

    l T5,读取第一字数据;

    l T6,读取第二字数据;

    l T7,读取第三字数据;

    l T8,读取第四字数据。

    多字读操作相较单字读操作稍微有一些不同,不同的地方除了读取数据的字变长以外,还有 TRP满足在最后两字之中。至于Verilog则可以这样描述,结果如代码19.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, pull up A10 to PR
    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 T[63:48] <= S_DQ; i <= i + 1'b1; end
    17.                    
    18.         6: // Read Data
    19.         begin T[47:32] <= S_DQ; i <= i + 1'b1; end
    20.                         
    21.         7: // Read Data
    22.         begin T[31:16] <= S_DQ; i <= i + 1'b1; end
    23.                         
    24.         8: // Read Data
    25.         begin T[15:0] <= S_DQ; i <= i + 1'b1; end 

    代码19.3

    代码19.3也没有什么好解释的,基本上完全根据图19.2描述。理解完毕以后,我们就可以开始建模了。

    clip_image006

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

    图19.3是SDRAM基础模块的建模图,这家伙比较实验十八,最大的区别就是iData与oData的位宽增大而已。

    sdram_funcmod.v

    clip_image008

    图19.4 SDRAM功能模块的建模图。

    图19.4是SDRAM功能模块的建模图,具体内容我们还是来看代码吧。

    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,  //2
    8.         output [12:0]S_A,  //12, CA0~CA8, RA0~RA12, BA0~BA1, 9+13+2 = 24;
    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 [63:0]iData,
    16.         output [63:0]oData
    17.    );

    以上内容为相关的出入端声明,注意第15~16行的位宽增大至64位。

    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.        

    以上内容为相关的常量声明。

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

    以上内容为相关的寄存器声明与复位操作,注意寄存器T是用来暂存读取数据。

    49.              else if( iCall[3] )
    50.                case( i )
    51.                    
    52.                    0: // Set IO to output State
    53.                    begin isOut <= 1'b1; i <= i + 1'b1; end
    54.                       
    55.                    1: // Send Active Command with Bank and Row address
    56.                    begin rCMD <= _ACT; rBA <= iAddr[23:22]; rA <= iAddr[21:9]; i <= i + 1'b1; end
    57.                         
    58.                  2: // wait TRCD 20ns
    59.                  if( C1 == TRCD -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    60.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end             
    61.                    
    62.                    /*********************************************/
    63.                    
    64.                   3: // Send Write command with row address, pull up A10 to PR
    65.                 begin rCMD <= _WR; rBA <= iAddr[23:22]; rA <= { 4'b0010, iAddr[8:0] }; D1 <= iData[63:48]; i <= i + 1'b1; end
    66.                         
    67.                    4:  
    68.                  begin rCMD <= _NOP; D1 <= iData[47:32]; i <= i + 1'b1; end
    69.                         
    70.                  5:
    71.                  begin rCMD <= _NOP; D1 <= iData[31:16]; i <= i + 1'b1; end
    72.                         
    73.                  6:
    74.                  begin rCMD <= _NOP; D1 <= iData[15:0]; i <= i + 1'b1; end
    75.                     
    76.                    /**********************************************/
    77.                         
    78.                  7: // wait TWR 2 clock
    79.                  if( C1 == TWR -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    80.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end  
    81.                         
    82.                  8: // wait TRP 20ns
    83.                  if( C1 == TRP -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    84.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end        
    85.                         
    86.                    /*******************/
    87.                         
    88.                    9: // Generate done signal
    89.                    begin isDone <= 1'b1; i <= i + 1'b1; end
    90.                        
    91.                  10:
    92.                  begin isDone <= 1'b0; i <= 4'd0; end
    93.    
    94.                endcase

    以上内容为部分核心操作。注意步骤3~6,D1用来驱动SD_Q,而iData赋值D1,次序由高至低。

    95.            else if( iCall[2] )
    96.                case( i )
    97.                    
    98.                  0:
    99.                  begin isOut <= 1'b0; D1 <= 16'd0; i <= i + 1'b1; end
    100.    
    101.                    1: // Send Active command with Bank and Row address
    102.                    begin rCMD <= _ACT; rBA <= iAddr[23:22]; rA <= iAddr[21:9]; i <= i + 1'b1; end
    103.                         
    104.                  2: // wait TRCD 20ns
    105.                  if( C1 == TRCD -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    106.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end 
    107.                
    108.                    /********************/
    109.                    
    110.                    3: // Send Read command and column address, pull up A10 to PR
    111.                    begin rCMD <= _RD; rBA <= iAddr[23:22]; rA <= { 4'b0010, iAddr[8:0]}; i <= i + 1'b1; end
    112.    
    113.                    4: // wait CL 3 clock
    114.                    if( C1 == CL -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    115.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end 
    116.                                       
    117.                    /********************/ 
    118.                    
    119.                    5: // Read Data
    120.                    begin T[63:48] <= S_DQ; i <= i + 1'b1; end
    121.                    
    122.                  6: // Read Data
    123.                    begin T[47:32] <= S_DQ; i <= i + 1'b1; end
    124.                         
    125.                  7: // Read Data
    126.                    begin T[31:16] <= S_DQ; i <= i + 1'b1; end
    127.                         
    128.                  8: // Read Data
    129.                    begin T[15:0] <= S_DQ; i <= i + 1'b1; end
    130.                         
    131.                    /********************/
    132.                
    133.                    9: // Generate done signal
    134.                    begin rCMD <= _NOP; isDone <= 1'b1; i <= i + 1'b1; end
    135.                        
    136.                  10:
    137.                  begin isDone <= 1'b0; i <= 4'd0; end
    138.    
    139.                endcase

    以上内容为部分核心操作。注意步骤5~8,寄存器T用来暂存读数据,次序由高至低。

    140.              else if( iCall[1] )
    141.                case( i )
    142.                    
    143.                  0: // Send Precharge Command
    144.                  begin rCMD <= _PR; i <= i + 1'b1; end
    145.                         
    146.                  1: // wait TRP 20ns
    147.                  if( C1 == TRP -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    148.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
    149.                         
    150.                    2: // Send Auto Refresh Command
    151.                    begin rCMD <= _AR; i <= i + 1'b1; end
    152.                   
    153.                    3: // wait TRRC 63ns
    154.                  if( C1 == TRRC -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    155.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
    156.                         
    157.                  4: // Send Auto Refresh Command
    158.                    begin rCMD <= _AR; i <= i + 1'b1; end
    159.                   
    160.                    5: // wait TRRC 63ns
    161.                  if( C1 == TRRC -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    162.                    else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
    163.                    
    164.                    /********************/
    165.                    
    166.                    6: // Generate done signal
    167.                    begin isDone <= 1'b1; i <= i + 1'b1; end
    168.                        
    169.                  7:
    170.                  begin isDone <= 1'b0; i <= 4'd0; end
    171.    
    172.                endcase

    以上内容为部分核心操作。刷新操作,基本上没有什么改变。

    173.              else if( iCall[0] )
    174.               case( i )
    175.                    
    176.                   0:  // delay 100us
    177.                   if( C1 == T100US -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    178.                   else begin C1 <= C1 + 1'b1; end 
    179.                   
    180.                   /********************/
    181.                   
    182.                   1: // Send Precharge Command
    183.                   begin rCMD <= _PR; { rBA, rA } <= 15'h3fff; i <= i + 1'b1; end
    184.                        
    185.                   2: // wait TRP 20ns
    186.                 if( C1 == TRP -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    187.                   else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
    188.                   
    189.                   3: // Send Auto Refresh Command
    190.                   begin rCMD <= _AR; i <= i + 1'b1; end
    191.                   
    192.                   4: // wait TRRC 63ns
    193.                 if( C1 == TRRC -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    194.                   else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
    195.                        
    196.                   5: // Send Auto Refresh Command
    197.                   begin rCMD <= _AR; i <= i + 1'b1; end
    198.                   
    199.                   6: // wait TRRC 63ns
    200.                 if( C1 == TRRC -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    201.                   else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
    202.                
    203.                   /********************/
    204.                   
    205.                   7: // Send LMR Cmd. Burst Read & Write,  3'b011 mean CAS latecy = 3, Sequentia 4 burst length
    206.                   begin rCMD <= _LMR; rBA <= 2'b11; rA <= { 3'd0, 1'b0, 2'd0, 3'b011, 1'b0, 3'b010 }; i <= i + 1'b1; end
    207.                        
    208.                 8: // Send 2 nop CLK for tMRD
    209.                 if( C1 == TMRD -1 ) begin C1 <= 14'd0; i <= i + 1'b1; end
    210.                   else begin rCMD <= _NOP; C1 <= C1 + 1'b1; end
    211.                   
    212.                   /********************/
    213.                   
    214.                   9: // Generate done signal
    215.                   begin isDone <= 1'b1; i <= i + 1'b1; end
    216.                        
    217.                 10:
    218.                 begin isDone <= 1'b0; i <= 4'd0; end
    219.                   
    220.                endcase
    221.      

    以上内容为部分核心操作。初始化操作,注意步骤7,Burst Length 设置为 3’b010。

    222.          assign { S_CKE, S_NCS, S_NRAS, S_NCAS, S_NWE } = rCMD;
    223.         assign { S_BA, S_A } = { rBA, rA };
    224.         assign S_DQM = rDQM;
    225.         assign S_DQ  = isOut ? D1 : 16'hzzzz;
    226.         assign oDone = isDone;
    227.         assign oData = T;
    228.    
    229.    endmodule

    以上内容为相关的输出驱动,D1驱动S_DQ,T驱动oData。

    sdram_ctrlmod.v

    该控制模块的内容基本上与实验十八一模一样,笔者就不重复粘贴了。

    sdram_demo.v

    clip_image010

    图19.5 实验十九的建模图。

    图19.5是实验十九的建模图,虽然外观上改变不大,最多只是Data的位宽改为64位而已 ... 话虽如此,核心操作则有点不同,具体的内容让我们来看代码吧。

    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 [63: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,2’b00} ),
    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 [21:0]D1;
    50.         reg [63: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 <= 22'd0;
    62.                          D2 <= 64'd0;
    63.                          D3 <= 64'd0;
    64.                          T <= 11'd0;
    65.                          isCall <= 2'b00;
    66.                          rTXD <= 1'b1;
    67.                 end

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

    68.             else 
    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 <= 22'd0; D2 <= 64'hAABBCCDDEEFF8899; 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; D1 <= 22'd0; end
    78.                         
    79.                         2:
    80.                         begin T <= { 2'b11, D3[63:56], 1'b0 }; i <= TXFUNC; Go <= i + 1'b1; end
    81.                         
    82.                         3:
    83.                         begin T <= { 2'b11, D3[55:48], 1'b0 }; i <= TXFUNC; Go <= i + 1'b1; end
    84.                         
    85.                         4:
    86.                         begin T <= { 2'b11, D3[47:40], 1'b0 }; i <= TXFUNC; Go <= i + 1'b1; end
    87.                         
    88.                         5:
    89.                         begin T <= { 2'b11, D3[39:32], 1'b0 }; i <= TXFUNC; Go <= i + 1'b1; end
    90.                         
    91.                         6:
    92.                         begin T <= { 2'b11, D3[31:24], 1'b0 }; i <= TXFUNC; Go <= i + 1'b1; end
    93.                         
    94.                         7:
    95.                         begin T <= { 2'b11, D3[23:16], 1'b0 }; i <= TXFUNC; Go <= i + 1'b1; end
    96.                                              
    97.                         8:
    98.                         begin T <= { 2'b11, D3[15:8], 1'b0 }; i <= TXFUNC; Go <= i + 1'b1; end
    99.                         
    100.                         9:
    101.                         begin T <= { 2'b11, D3[7:0], 1'b0 }; i <= TXFUNC; Go <= i + 1'b1; end
    102.                         
    103.                          10:
    104.                         i <= i;
    105.                         
    106.                        /******************************/
    107.                     

    以上内容为部分核心操作。步骤0将64位的数据写入地址0,步骤1则将数据从地址0读取。步骤2~9则是轮番将数据送出去。

    108.                          16,17,18,19,20,21,22,23,24,25,26:
    109.                         if( C1 == B115K2 -1 ) begin C1 <= 11'd0; i <= i + 1'b1; end
    110.                         else begin rTXD <= T[i - 16]; C1 <= C1 + 1'b1; end
    111.                         
    112.                         27:
    113.                         i <= Go;
    114.                         
    115.                endcase
    116.    
    117.          assign S_CLK = CLOCK2;
    118.          assign TXD = rTXD;
    119.    
    120.    endmodule

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

    细节一:完整的个体模块

    本实验的SDRAM基础模块已经准备就绪。

    细节二:读写地址的驱动方式

    1.    sdram_basemod
    2.    (   
    3.        ... 
    4.        iAddr( {D1,2’b00} ),
    5.        ...
    6.    );
    7.    reg [21:0]D1;
    8.    ...
    9.    always @ ( posedge CLOCK1 )
    10.         ...
    11.         case( i )
    12.             0:
    13.             if( ... ) ...
    14.             else D1 <= 22'd0; ...

    代码19.4

    代码19.4是sdram_demo的部分内容,其中iAddr由22位宽的D1与2’b00联合驱动,好奇的朋友一定会觉得疑惑“为什么”?其实这是经过深思以后的写法。实验十九是多字读写操作,其中长度为4,或者说地址的偏移量为4,所以iAddr[1:0] 所指定的范围基本作废。为了正式这点问题,代码19.4需要这样表达。

    1.    sdram_basemod
    2.    (   
    3.        ... 
    4.        iAddr( D1 ),
    5.        ...
    6.    );
    7.    reg [23:0]D1;
    8.    ...
    9.    always @ ( posedge CLOCK1 )
    10.         ...
    11.         case( i )
    12.             0:
    13.             if( ... ) ...
    14.             else D1 <= 24'd1; ...

    代码19.5

    如代码19.5所示,假设我们无视这个问题,直接使用24位宽的D1驱动iAddr,然后将数据写入地址24’d1。根据SDRAM的内部操作,数据会依序写入地址为1234,而不是 0123 或者 4567 之类 ... 如此一来,我们会不小心破坏地址的偏移量。

  • 相关阅读:
    11111 Generalized Matrioshkas
    Uva 442 Matrix Chain Multiplication
    Uva 10815 Andy's First Dictionary
    Uva 537 Artificial Intelligence?
    Uva 340 MasterMind Hints
    SCAU 9508 诸葛给我牌(水泥题)
    Uva 10420 List of Conquests(排序水题)
    Uva 409 Excuses, Excuses!
    10/26
    11/2
  • 原文地址:https://www.cnblogs.com/alinx/p/4398673.html
Copyright © 2011-2022 走看看