• 【黑金原创教程】【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 之类 ... 如此一来,我们会不小心破坏地址的偏移量。

  • 相关阅读:
    部分网络加载预训练模型代码实现
    数据不平衡处理方法
    面试题目汇总
    多线程和多进程
    数据结构知识点总结
    GBDT和XGBoost的区别
    GBDT和随机森林的区别
    机器学习-特征处理
    一篇写得很好的关于lct的博客
    Count and Say 2014/10/23
  • 原文地址:https://www.cnblogs.com/alinx/p/4398673.html
Copyright © 2020-2023  润新知