【黑金原创教程】【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表示实验成功。

你可能感兴趣的:(FPGA)