1. 程式人生 > >【黑金原創教程】【FPGA那些事兒-驅動篇I 】實驗十九:SDRAM模組② — 多字讀寫

【黑金原創教程】【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 之類 ... 如此一來,我們會不小心破壞地址的偏移量。

相關推薦

黑金原創教程FPGA那些事兒-驅動I 實驗SDRAM模組② —

實驗十九:SDRAM模組② — 多字讀寫 表示19.1 Mode Register的內容。 Mode Register A12 A11 A10 A9 A8 A7 A6 A5 A4 A

黑金原創教程FPGA那些事兒-驅動I 實驗流水燈模組

實驗一:流水燈模組 對於發展商而言,動土儀式無疑是最重要的任務。為此,流水燈實驗作為低階建模II的動土儀式再適合不過了。廢話少說,我們還是開始實驗吧。 圖1.1 實驗一建模圖。 如圖1.1 所示,實驗一有名為 led_funcmod的功能模組。如果無視環境訊號(時鐘訊號還有復位訊號),該功能模組只有

黑金原創教程FPGA那些事兒-驅動I 連載導讀

前言: 無數晝夜的來回輪替以後,這本《驅動篇I》終於編輯完畢了,筆者真的感動到連鼻涕也流下來。所謂驅動就是認識硬體,還有前期建模。雖然《驅動篇I》的硬體都是我們熟悉的老友記,例如UART,VGA等,但是《驅動篇I》貴就貴在建模技巧的昇華,亦即低階建模II。 話說低階建模II,讀過《建模篇》的朋友多少也會面

黑金原創教程FPGA那些事兒-驅動I 實驗按鍵模組② — 點選與長點選

實驗三:按鍵模組② — 點選與長點選 實驗二我們學過按鍵功能模組的基礎內容,其中我們知道按鍵功能模組有如下操作: l 電平變化檢測; l 過濾抖動; l 產生有效按鍵。 實驗三我們也會z執行同樣的事情,不過卻是產生不一樣的有效按鍵: l 按下有效(點選); l 長按下有效(長點選)。 圖3

黑金原創教程FPGA那些事兒-驅動I 實驗按鍵模組

實驗二:按鍵模組① - 消抖 按鍵消抖實驗可謂是經典中的經典,按鍵消抖實驗雖曾在《建模篇》出現過,而且還惹來一堆麻煩。事實上,筆者這是在刁難各位同學,好讓對方的慣性思維短路一下,但是慘遭口水攻擊 ... 面對它,筆者宛如被甩的男人,對它又愛又恨。不管怎麼樣,如今 I’ll be back,筆者再也不會重複一

黑金原創教程FPGA那些事兒-驅動I 實驗數碼管模組

實驗六:數碼管模組 有關數碼管的驅動,想必讀者已經學爛了 ... 不過,作為學習的新儀式,再爛的東西也要溫故知新,不然學習就會不健全。黑金開發板上的數碼管資源,由始至終都沒有改變過,筆者因此由身懷念。為了點亮多位數碼管從而顯示數字,一般都會採用動態掃描,然而有關動態掃描的資訊請怒筆者不再重複。在此,同樣也是

黑金原創教程FPGA那些事兒-驅動I 實驗按鍵模組③ — 單擊與雙擊

實驗四:按鍵模組③ — 單擊與雙擊 實驗三我們建立了“點選”還有“長點選”等有效按鍵的多功能按鍵模組。在此,實驗四同樣也是建立多功能按鍵模組,不過卻有不同的有效按鍵。實驗四的按鍵功能模組有以下兩項有效按鍵: l 單擊(按下有效); l 雙擊(連續按下兩下有效)。 圖4.1 單擊有效按鍵,時序示意圖

黑金原創教程FPGA那些事兒-驅動I 實驗按鍵模組④ — 點選,長點選,雙擊

實驗五:按鍵模組④ — 點選,長點選,雙擊 實驗二至實驗四,我們一共完成如下有效按鍵: l 點選(按下有效) l 點選(釋放有效) l 長擊(長按下有效) l 雙擊(連續按下有效) 然而,不管哪個實驗都是隻有兩項“功能”的按鍵模組而已,如今我們要建立三項“功能”的按鍵模組,亦即點選(按下有效),長

黑金原創教程FPGA那些事兒-驅動I 原創教程連載導讀連載完成,共二

前言: 無數晝夜的來回輪替以後,這本《驅動篇I》終於編輯完畢了,筆者真的感動到連鼻涕也流下來。所謂驅動就是認識硬體,還有前期建模。雖然《驅動篇I》的硬體都是我們熟悉的老友記,例如UART,VGA等,但是《驅動篇I》貴就貴在建模技巧的昇華,亦即低階建模II。 話說低階建模II,讀過《建模篇》的朋友多少也會面

黑金原創教程FPGA那些事兒-驅動I 實驗SDRAM模組④ — 頁 β

實驗二十一:SDRAM模組④ — 頁讀寫 β 未進入主題之前,讓我們先來談談一些重要的體外話。《整合篇》之際,筆者曾經比擬Verilog如何模仿for迴圈,我們知道for迴圈是順序語言的產物,如果Verilog要實現屬於自己的for迴圈,那麼它要考慮的東西除了步驟以外,還有非常關鍵的時鐘。 for(

黑金原創教程FPGA那些事兒-驅動I 實驗PS/2模組④ — 普通滑鼠

實驗十:PS/2模組④ — 普通滑鼠 學習PS/2鍵盤以後,接下來就要學習 PS/2 滑鼠。PS/2滑鼠相較PS/2鍵盤,驅動難度稍微高了一點點,因為FPGA(從機)不僅僅是從PS/2滑鼠哪裡讀取資料,FPGA還要往滑鼠裡寫資料 ... 反之,FPGA只要對PS/2鍵盤讀取資料即可。然而,最傷腦筋的地方就在

黑金原創教程FPGA那些事兒-驅動I 實驗SDRAM模組① — 單字

實驗十八:SDRAM模組① — 單字讀寫 筆者與SDRAM有段不短的孽緣,它作為冤魂日夜不斷糾纏筆者。筆者嘗試過許多方法將其退散,不過屢試屢敗的筆者,最終心情像橘子一樣橙。《整合篇》之際,筆者曾經大戰幾回兒,不過內容都是點到即止。最近它破蠱而出,日夜不停:“好~痛苦!好~痛苦!”地呻吟著,嚇得筆者不敢半夜如

黑金原創教程FPGA那些事兒-驅動I 實驗TFT模組

實驗二十七:TFT模組 - 顯示 所謂TFT(Thin Film Transistor)就是眾多LCD當中,其中一種支援顏色的LCD,相較古老的點陣LCD(12864笑),它可謂高階了。黑金的TFT LCD除了320×240大小以外,內建SSD1289控制器,同時也是獨立模組。事實上,無論是驅動點陣LCD還

黑金原創教程FPGA那些事兒-驅動I 實驗十三串列埠模組② — 接收

實驗十三:串列埠模組② — 接收 我們在實驗十二實現了串列埠傳送,然而這章實驗則要實現串列埠接收 ... 在此,筆者也會使用其它思路實現串列埠接收。 圖13.1 模組之間的資料傳輸。 假設我們不考慮波特率,而且一幀資料之間的傳輸也只是發生在FPGA之間,即兩隻模組之間互轉,並且兩塊模組都使用相同的時

黑金原創教程FPGA那些事兒-驅動I 實驗PS/2模組① — 鍵盤

實驗七:PS/2模組① — 鍵盤 實驗七依然也是熟爛的PS/2鍵盤。相較《建模篇》的PS/2鍵盤實驗,實驗七實除了實現基本的驅動以外,我們還要深入解PS/2時序,還有PS/2鍵盤的行為。不過,為了節省珍貴的頁數,怒筆者不再重複有關PS/2的基礎內容,那些不曉得的讀者請複習《建模篇》或者自行谷歌一下。 市場

黑金原創教程FPGA那些事兒-驅動I 實驗PS/2模組③ — 鍵盤與組合鍵

實驗九:PS/2模組③ — 鍵盤與多組合鍵 筆者曾經說過,通碼除了單位元組以外,也有雙位元組通碼,而且雙位元組通碼都是 8’hE0開頭,別名又是 E0按鍵。常見的的E0按鍵有,<↑>,<↓>,<←>,<→>,<HOME>,<PRTSC>

黑金原創教程FPGA那些事兒-驅動I 實驗SDHC模組

實驗二十五:SDHC模組 筆者曾經說過,SD卡發展至今已經衍生許多版本,實驗二十四就是針對版本SDV1.×的SD卡。實驗二十四也說過,CMD24還有CMD17會故意偏移地址29,讓原本範圍指向從原本的232 變成 223,原因是SD卡讀寫一次都有512個位元組。為此我們可以這樣計算: SDV1.x = 2

黑金原創教程FPGA那些事兒-驅動I 實驗SDRAM模組③ — 頁 α

實驗二十:SDRAM模組③ — 頁讀寫 α 完成單字讀寫與多字讀寫以後,接下來我們要實驗頁讀寫。醜話當前,實驗二十的頁讀寫只是實驗性質的東西,其中不存在任何實用價值,筆者希望讀者可以把它當成頁讀寫的熱身運動。 表示20.1 Mode Register的內容。 Mode Register

黑金原創教程FPGA那些事兒-驅動I 實驗TFT模組

實驗二十八:TFT模組 - 觸屏 讀者在上一個實驗所玩弄過的 TFT LCD模組,除了顯示大小為 320 × 240,顏色為16位RGB的影象資訊以外,它還支援觸屏。所謂觸屏就是滑鼠還有鍵盤以外的輸入手段,例如現在流行平板還有智慧手機,觸屏輸入對我們來說,已經成為日常的一部分。描述語言一門偏向硬體的語言

黑金原創教程FPGA那些事兒-驅動I 實驗SDRAM模組⑤ — FIFO

經過漫長的戰鬥以後,我們終於來到最後。對於普通人而言,頁讀寫就是一名戰士的墓碑(最終戰役) ... 然而,怕死的筆者想透過這個實驗告訴讀者,旅程的終點就是旅程的起點。一直以來,筆者都在煩惱“SDRAM是否應該成為儲存類?”SDRAM作為一介儲存資源(儲存器),它的好處就是大容量空間,壞處則就是麻煩的控制規