【黑金原创教程】【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 |
|
| ||||||||||||||||||||||||||||||||||||||
|
|
所謂頁讀寫就是全列讀寫,而且表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的地址偏移量。
頁寫操作:
圖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命令。
頁讀操作:
圖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命令以示結束頁讀操作。理解完畢以后我們便可以開始建模了。
圖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
圖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那些事儿-驱动篇I 】实验二十:SDRAM模块③ — 页读写 α...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Socket IO与NIO(三)
- 下一篇: linux监控脚本