【黑金原創教程】【FPGA那些事兒-驅動篇I 】實驗二十二:SDRAM模塊⑤ — FIFO讀寫


 

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

相比之下,片上內存無論是控制的難度,還是溝通的速率,它都遠遠領先SDRAM。俗語常說,愈是強力的資源愈是珍貴 ... 對此,片上內容的容量可謂是稀罕的程度。實驗二十二的要求非常單純:

”請問如何建立基於SDRAM儲存資源的FIFO存儲模塊呢?“,筆者問道。

clip_image002

圖22.1 SDRAM基礎模塊。

圖22.1是基於實驗十八修改而成的SDRAM基礎模塊,修改對象除了SDRAM控制模塊以外,SDRAM功能模塊保持實驗十八的狀態,即單字讀寫。SDRAM控制模塊,除了多出Tag以外,Addr的驅動也由該模塊負責。具體的內容,讓我們來看代碼吧:

1.    module sdram_ctrlmod
2.    (
3.        input CLOCK,
4.        input RESET,
5.        input [1:0]iCall, // [1]Write, [0]Read
6.        output [1:0]oDone,
7.        output [3:0]oCall,
8.        input iDone,
9.        output [23:0]oAddr,
10.        output [1:0]oTag
11.    );
12.        parameter WRITE = 4'd1, READ = 4'd4, REFRESH = 4'd7, INITIAL = 4'd8;
13.        parameter TREF = 11'd1040;
14.        

以上內容為相關的出入端聲明以及常量。其中多了24位寬的oAddr與2位寬的oTag。

15.         reg [1:0]C7;
16.         reg [1:0]isDo;
17.         
18.         always @ ( posedge CLOCK or negedge RESET ) // sub
19.             if( !RESET )
20.                  begin
21.                         C7 <= 2'b10;
22.                         isDo <= 2'b00;
23.                    end
24.              else
25.                  begin
26.                    
27.                        if( iCall[1] & C7[1] ) isDo[1] <= 1'b1;
28.                        else if( iCall[0] & C7[0] ) isDo[0] <= 1'b1;
29.                         
30.                        if( isDo[1] & isDone[1] ) isDo[1] <= 1'b0;
31.                        else if( isDo[0] & isDone[0] ) isDo[0] <= 1'b0;
32.                    
33.                        if( isDone ) C7 <= {isDo[0],isDo[1]};
34.                        else if( iCall ) C7 <= { C7[0], C7[1] };
35.                    
36.                    end
37.        

以上內容為輪流協調的周邊操作。具體內容與實驗十七一樣。

38.        reg [3:0]i;
39.        reg [10:0]C1;
40.        reg [3:0]isCall; //[3]Write [2]Read [1]A.Refresh [0]Initial
41.        reg [1:0]isDone;
42.        reg [23:0]D1;
43.        reg [24:0]C2,C3;  // N + 1
44.        
45.        always @ ( posedge CLOCK or negedge RESET ) // core
46.            if( !RESET )
47.                 begin
48.                         i <= INITIAL;          // Initial SDRam at first 
49.                         C1 <= 11'd0;
50.                        isCall <= 4'b0000;
51.                        isDone <= 2'b00;
52.                        D1 <= 24'd0;
53.                        C2 <= 25'd0;
54.                        C3 <= 25'd0;
55.                  end

以上內容為相關的寄存器聲明與復位操作。其中C2是寫指針,C3是讀指針,位寬為oAddr + 1。D用來驅動oAddr。

56.             else 
57.                 case( i )
58.                  
59.                        0: // IDLE
60.                        if( C1 >= TREF ) begin C1 <= 11'd0;  i <= REFRESH; end
61.                        else if( isDo[1] ) begin C1 <= C1 + 1'b1; i <= WRITE; end 
62.                        else if( isDo[0] ) begin C1 <= C1 + 1'b1; i <= READ; end 
63.                         else begin C1 <= C1 + 1'b1; end
64.    
65.                        /***********************/
66.                        

以上內容為部分核心內容。步驟0是待機狀態,其中61~62行改為 isDo[1] 與 isDo[2]。

67.                        1: //Write 
68.                        if( iDone ) begin isCall[3] <= 1'b0; C1 <= C1 + 1'b1; i <= i + 1'b1; end
69.                        else begin isCall[3] <= 1'b1; D1 <= C2[23:0]; C1 <= C1 + 1'b1; end
70.                        
71.                        2:
72.                        begin C2 <= C2 + 1'b1; isDone[1] <= 1'b1; C1 <= C1 + 1'b1; i <= i + 1'b1; end
73.                        
74.                        3:
75.                        begin isDone[1] <= 1'b0; C1 <= C1 + 1'b1; i <= 4'd0; end
76.                        
77.                        /***********************/
78.                        

以上內容為部分核心內容。步驟1~3是寫操作,步驟1將C2[23:0]的內容賦值D。步驟2~3產生完成信號之余也遞增C2.

79.                        4: // Read
80.                        if( iDone ) begin isCall[2] <= 1'b0; C1 <= C1 + 1'b1; i <= i + 1'b1; end
81.                        else begin isCall[2] <= 1'b1; D1 <= C3[23:0]; C1 <= C1 + 1'b1; end
82.                        
83.                        5:
84.                        begin C3 <= C3 + 1'b1; isDone[0] <= 1'b1; C1 <= C1 + 1'b1; i <= i + 1'b1; end
85.                        
86.                        6:
87.                        begin isDone[0] <= 1'b0; C1 <= C1 + 1'b1; i <= 4'd0; end
88.                        
89.                        /***********************/
90.                        

以上內容為部分核心內容。步驟4~6是寫操作,步驟4將C3[23:0]的內容賦值D。步驟5~7產生完成信號之余也遞增C3.

91.                        7: // Auto Refresh 
92.                        if( iDone ) begin isCall[1] <= 1'b0; i <= 4'd0; end
93.                        else begin isCall[1] <= 1'b1; end
94.                        
95.                        /***********************/
96.                        
97.                        8: // Initial 
98.                        if( iDone ) begin isCall[0] <= 1'b0; i <= 4'd0; end
99.                        else begin isCall[0] <= 1'b1; end
100.                        
101.                  endcase
102.        

以上內容為部分核心內容。步驟7~8保持不變。

103.        assign oDone = isDone;
104.        assign oCall = isCall;
105.        assign oAddr = D1;
106.        assign oTag[1] = ( C2[24]^C3[24] & C2[23:0] == C3[23:0] ); 
107.         assign oTag[0] = ( C2 == C3 ); 
108.        
109.    endmodule

以上內容為相關的輸出驅動。D1驅動oAddr,第106~107行是寫滿狀態與讀空狀態的聲明。

sdram_funcmod.v

該功能模塊與實驗十八的內容一模一樣。

sdram_demo.v

該組合模塊的連線部署完全參照圖22.1。

1.    module sdram_basemod
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 [1:0]iCall,
13.         output [1:0]oDone,
14.         output [1:0]oTag,
15.         input [15:0]iData,
16.         output [15:0]oData
17.    ); 
18.         wire [3:0]CallU1; // [3]Refresh, [2]Read, [1]Write, [0]Initial
19.         wire [23:0]AddrU2;
20.         
21.        sdram_ctrlmod U1
22.         (
23.              .CLOCK( CLOCK ),
24.              .RESET( RESET ),
25.              .iCall( iCall ),       // < top ,[1]Write [0]Read
26.              .oDone( oDone ),     // > top ,[1]Write [0]Read
27.              .oAddr( AddrU2 ),    // > U2
28.              .oTag( oTag ),        // > top
29.              .oCall( CallU1 ),      // > U2 
30.              .iDone( DoneU2 )           // < U2
31.         );
32.         
33.         wire DoneU2;
34.         
35.         sdram_funcmod U2
36.         (
37.              .CLOCK( CLOCK ),
38.              .RESET( RESET ),
39.              .S_CKE( S_CKE ),           // > top
40.              .S_NCS( S_NCS ),           // > top
41.              .S_NRAS( S_NRAS ),         // > top
42.              .S_NCAS( S_NCAS ),         // > top
43.              .S_NWE( S_NWE ),         // > top
44.              .S_BA( S_BA ),           // > top
45.              .S_A( S_A ),             // > top
46.              .S_DQM( S_DQM ),         // > top
47.              .S_DQ( S_DQ ),           // <> top        
48.              .iCall( CallU1 ),            // < U1
49.              .oDone( DoneU2 ),          // > U1
50.              .iAddr( AddrU2 ),          // < U1
51.              .iData( iData ),               // < top
52.              .oData( oData )           // > top
53.         );
54.         
55.    endmodule

連線內容請自己看着辦吧。

sdram_demo.v

clip_image004

圖22.3 實驗二十二的建模圖。

圖22.3是實驗二十二的建模圖,左邊的周邊操作負責寫入數據,右邊的核心操作負責讀取數據並且經由TXD發送出去。具體內容我們還是來看代碼吧。

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.         wire [1:0]TagU2;
25.         
26.         sdram_basemod U2
27.         (
28.             .CLOCK( CLOCK1 ),
29.             .RESET( RESET ),
30.              .S_CKE( S_CKE ),
31.              .S_NCS( S_NCS ),
32.              .S_NRAS( S_NRAS ),
33.              .S_NCAS( S_NCAS ),
34.              .S_NWE( S_NWE ),
35.              .S_A( S_A ),
36.              .S_BA( S_BA ),
37.              .S_DQM( S_DQM ),
38.              .S_DQ( S_DQ ),
39.              .iCall( {isWR,isRD} ),
40.              .oDone( DoneU2 ),
41.              .iData( D2 ),
42.              .oData( DataU2 ),
43.              .oTag( TagU2 )
44.         );

以上內容為SDRAM基礎模塊的實例化,注意第39行的iCall是由 isWR與isRD聯合驅動。此外,第43行也多了oTag。

46.         reg [5:0]i;
47.         reg [15:0]D2;
48.         reg isWR;
49.         
50.         always @ ( posedge CLOCK1 or negedge RESET )
51.             if( !RESET )
52.                 begin
53.                           i <= 6'd0;
54.                          D2 <= 16'hA000;
55.                          isWR <= 1'b0;
56.                 end
57.             else 
58.                 case( i )
59.                 
60.                          0:
61.                         if( !TagU2[1] ) i <= i + 1'b1;
62.                        
63.                         1:
64.                         if( DoneU2[1] ) begin isWR <= 1'b0; i <= i + 1'b1; end
65.                         else begin isWR <= 1'b1; end
66.                         
67.                         2:
68.                         if( D2 == 16'hA1FF ) i <= i + 1'b1;
69.                         else begin D2[11:0] <= D2[11:0] +  1'b1; i <= 6'd0; end
70.                         
71.                         3:
72.                         i <= i;
73.                    
74.                endcase
75.                

以上內容為寫作用的周邊操作。步驟0檢測是否寫滿,步驟1寫入數據,步驟2判斷是否寫滿512次,不是的話就遞增內容。步驟3是寫完發呆。

76.         reg [5:0]j,Go;
77.         reg [10:0]C1;
78.         reg [15:0]D3;
79.         reg [10:0]T;
80.         reg isRD;
81.         reg rTXD;    
82.         
83.         parameter B115K2 = 11'd1157, TXFUNC = 6'd16;
84.                
85.        always @ ( posedge CLOCK1 or negedge RESET )
86.             if( !RESET )
87.                 begin
88.                     j <= 6'd0;
89.                          Go <= 6'd0;
90.                          C1 <= 11'd0;
91.                          D3 <= 16'd0;
92.                          T <= 11'd0;
93.                          isRD <= 1'b0;
94.                          rTXD <= 1'b1;
95.                 end
96.             else 
97.                 case( j )
98.                 
99.                         0:
100.                         if( !TagU2[0] ) j <= j + 1'b1;
101.                         
102.                         1:
103.                         if( DoneU2[0] ) begin D3 <= DataU2; isRD <= 1'b0; j <= j + 1'b1; end
104.                         else begin isRD <= 1'b1; end
105.                         
106.                         2:
107.                         begin T <= { 2'b11, D3[15:8], 1'b0 }; j <= TXFUNC; Go <= j + 1'b1; end
108.                         
109.                         3:
110.                         begin T <= { 2'b11, D3[7:0], 1'b0 }; j <= TXFUNC; Go <= j + 1'b1; end
111.                         
112.                         4:
113.                         if( D3 == 16'hA1FF ) j <= j + 1'b1; 
114.                         else j <= 6'd0;
115.                         
116.                        5:
117.                         j <= j;
118.                         
119.                        /******************************/
120.        

以上內容為部分核心操作。步驟0檢測是否讀空,步驟1讀出數據,步驟2~3將數據發送數據,步驟4判斷是否執行512次?如果不是的話就返回步驟0,是的話就遞增i進入發呆的步驟5。

121.                          16,17,18,19,20,21,22,23,24,25,26:
122.                         if( C1 == B115K2 -1 ) begin C1 <= 11'd0; j <= j + 1'b1; end
123.                         else begin rTXD <= T[j - 16]; C1 <= C1 + 1'b1; end
124.                         
125.                         27:
126.                         j <= Go;
127.                         
128.                endcase
129.    
130.         assign S_CLK = CLOCK2;
131.         assign TXD = rTXD;
132.    
133.    endmodule

以上內容為核心操作以及輸出驅動·。綜合完畢便下載程序,如果串口調試軟件出現 A000~A1FF,表示實驗成功。

細節一:完整的個體模塊

本實驗的SDRAM基礎模塊已經准備就緒。

細節二:小談儲存類

FIFO機制的SDRAM很可能實用性不強。相對低級建模II而言,SDRAM已經脫離死板的印象,任何畸形的儲存方式,都有可能實現在任何儲存資源之上。舉例而言,片上內存儲存資源可以實現FIFO功能,IIC儲存資源也可以實現FIFO功能,SDRAM儲存資源也可以實現FIFO功能。

如果按照這條思路逆向思考的話,如果SDRAM儲存資源可以實現功能C,那么IIC儲存資源還有片上內存儲存資源同樣也可以實現功能C。如此一來,建模的自由度會大大增高,喜愛建模的孩子也會開心至極。如果讀者是變態,那么一塊小小的SDRAM儲存資源實現多功能讀寫如:單字讀寫,多字讀寫,頁讀寫,甚至FIFO讀寫,集於一身是有可能的。不管怎么樣,實驗二十二所要表達的信息已經非常清晰,即儲存類的伸縮性與可塑性。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM