生成 DDR2 IP 后就可以使用了,網絡上也很多直接對 DDR2 IP 操作的例程,但其實這樣還不夠好,我們可以對這個 DDR2 IP 進行再次封裝,讓它變得更加好用。現在試着封裝一下,之前的 DDR2 IP 名字就是 DDR2.v,這個封裝就命名為 DDR2_burst,其主要作用是完成一次 DDR2 的突發讀寫,即外界可以任意設置突發長度,在這個模塊將這個任意的突發長度轉換為突發長度 4 寫進 DDR2 IP 里。
封裝 DDR2 IP 有常見的兩種方式,一種是設計 DDR2_burst 和 DDR2 IP 外部互聯,再用第三個 .v 文件將這兩者連線,如下所示:
另一種是直接將 DDR2_IP 放到 DDR2_burst 代碼里面例化,如下所示:
顯然,第二種比較簡潔,文件較少。
一、參數集 DDR2_param
先給出參數集,方便移植。命名為 DDR2_param.v,內容如下:
//************************************************************************** // *** 名稱 : DDR2_param.v // *** 作者 : xianyu_FPGA // *** 博客 : https://www.cnblogs.com/xianyufpga/ // *** 日期 : 2020年6月 // *** 描述 : DDR2參數,PLL 100Mhz,DDR2 166.7Mhz,Full Rate //************************************************************************** `define MEM_ADDR_W 13 //DDR2 地址位寬 `define MEM_BANK_W 3 //DDR2 bank位寬 `define MEM_DM_W 4 //DDR2 dm位寬 `define MEM_DQ_W 32 //DDR2 數據位寬,一片16兩片32 `define MEM_DQS_W 4 //DDR2 DQS位寬 `define LOCAL_DATA_W 64 //DDR2 IP核全速率數據位寬 `define LOCAL_ADDR_W 25 //DDR2 IP核全速率地址位寬 `define LOCAL_SIZE_W 3 //DDR2 IP核全速率local_size位寬 `define LOCAL_BE_W 8 //DDR2 IP核全速率local_be位寬 `define BURST_W 14 //burst長度位寬,burst_len + BURST_SIZE
burst 長度位寬為什么是 14,下一篇博客會說明,現在記住這個數字。
二、DDR2_burst
1 `include "DDR2_param.v" 2 //************************************************************************** 3 // *** 名稱 : DDR2_burst.v 4 // *** 作者 : xianyu_FPGA 5 // *** 博客 : https://www.cnblogs.com/xianyufpga/ 6 // *** 日期 : 2020年6月 7 // *** 描述 : 完成一次DDR2的突發讀寫 8 //************************************************************************** 9 10 module DDR2_burst 11 //============================< 端口 >====================================== 12 ( 13 //DDR2 IP核接口 ----------------------------------------- 14 input pll_ref_clk , //DDR2 參考時鍾 15 input global_reset_n , //全局復位信號,連接外部復位 16 output phy_clk , //DDR2 IP核工作時鍾 17 output reset_phy_clk_n , //DDR2 IP核同步后的復位信號 18 output local_init_done , //DDR2 IP核初始化完成信號 19 //突發讀寫接口 ------------------------------------------ 20 input burst_rdreq , //突發讀請求 21 input burst_wrreq , //突發寫請求 22 input [`BURST_W -1:0] burst_rdlen , //突發讀長度 23 input [`BURST_W -1:0] burst_wrlen , //突發寫長度 24 input [`LOCAL_ADDR_W -1:0] burst_rdaddr , //突發讀地址 25 input [`LOCAL_ADDR_W -1:0] burst_wraddr , //突發寫地址 26 output [`LOCAL_DATA_W -1:0] burst_rddata , //突發讀數據 27 input [`LOCAL_DATA_W -1:0] burst_wrdata , //突發寫數據 28 output burst_rdack , //突發讀應答,連接FIFO 29 output burst_wrack , //突發寫應答,連接FIFO 30 output reg burst_rddone , //突發讀完成信號 31 output reg burst_wrdone , //突發寫完成信號 32 //DDR2端口 ---------------------------------------------- 33 output mem_odt , //DDR2片上終結信號 34 output mem_cs_n , //DDR2片選信號 35 output mem_cke , //DDR2時鍾使能信號 36 output [`MEM_ADDR_W -1:0] mem_addr , //DDR2地址總線 37 output [`MEM_BANK_W -1:0] mem_ba , //DDR2BANK信號 38 output mem_ras_n , //DDR2行地址選擇信號 39 output mem_cas_n , //DDR2列地址選擇信號 40 output mem_we_n , //DDR2寫使能信號 41 output [`MEM_DM_W -1:0] mem_dm , //DDR2數據掩膜信號 42 inout mem_clk , //DDR2時鍾信號 43 inout mem_clk_n , //DDR2時鍾反相信號 44 inout [`MEM_DQ_W -1:0] mem_dq , //DDR2數據總線 45 inout [`MEM_DQS_W -1:0] mem_dqs //DDR2數據源同步信號 46 ); 47 //============================< 信號 >====================================== 48 wire rst_n ; //本模塊復位信號 49 reg [ 4:0] state ; //狀態機 50 reg [ `BURST_W -1:0] rdaddr_cnt ; //讀地址計數器 51 reg [ `BURST_W -1:0] rddata_cnt ; //讀數據計數器 52 reg [ `BURST_W -1:0] wrburst_cnt ; //一次突發寫內的計數器 53 reg [ `BURST_W -1:0] wraddr_cnt ; //寫地址計數器 54 reg [ `BURST_W -1:0] rdlen ; //寫突發長度 55 reg [ `BURST_W -1:0] wrlen ; //讀突發長度 56 wire local_burstbegin ; //DDR2 IP核突發起始信號 57 reg [`LOCAL_SIZE_W -1:0] local_size ; //DDR2 IP核突發大小 58 reg [`LOCAL_ADDR_W -1:0] local_address ; //DDR2 IP核地址總線 59 wire local_write_req ; //DDR2 IP核寫請求信號 60 wire local_read_req ; //DDR2 IP核讀請求信號 61 wire [`LOCAL_DATA_W -1:0] local_wdata ; //DDR2 IP核寫數據總線 62 wire [`LOCAL_DATA_W -1:0] local_rdata ; //DDR2 IP核讀數據總線 63 wire local_ready ; //DDR2 IP核准備好信號 64 wire local_rdata_valid ; //DDR2 IP核讀數據有效信號 65 //============================< 參數 >====================================== 66 parameter WRBURST_SIZE = `BURST_W'd2 ; //總線寫突發大小 67 parameter RDBURST_SIZE = `BURST_W'd2 ; //總線讀突發大小 68 //------------------------------------------------------- 69 parameter IDLE = 5'b00001 ; //空閑狀態 70 parameter WR_RDY = 5'b00010 ; //寫准備狀態 71 parameter WR = 5'b00100 ; //寫狀態 72 parameter RD_ADDR = 5'b01000 ; //讀狀態 73 parameter RD_WAIT = 5'b10000 ; //讀等待狀態 74 //========================================================================== 75 //== DDR2 IP核,PLL 100Mhz,DDR2 166.7Mhz,Full Rate 76 //========================================================================== 77 DDR2 u_DDR2 78 ( 79 .pll_ref_clk (pll_ref_clk ), //DDR2 參考時鍾 80 .global_reset_n (global_reset_n ), //全局復位信號 81 .soft_reset_n (1'b1 ), //軟復位信號 82 .local_address (local_address ), //DDR2 IP核地址總線 83 .local_write_req (local_write_req ), //DDR2 IP核寫請求信號 84 .local_read_req (local_read_req ), //DDR2 IP核讀請求信號 85 .local_burstbegin (local_burstbegin ), //DDR2 IP核突發起始信號 86 .local_wdata (local_wdata ), //DDR2 IP核寫數據總線 87 .local_be (8'b1111_1111 ), //DDR2 IP核字節使能信號 88 .local_size (local_size ), //DDR2 IP核突發大小 89 .local_ready (local_ready ), //DDR2 IP核准備好信號 90 .local_rdata (local_rdata ), //DDR2 IP核讀數據總線 91 .local_rdata_valid (local_rdata_valid ), //DDR2 IP核讀數據有效信號 92 .local_refresh_ack ( ), //DDR2 IP核自刷新應答信號 93 .local_init_done (local_init_done ), //DDR2 IP核初始化完成信號 94 //--------------------------------------------------- 95 .mem_odt (mem_odt ), //DDR2片上終結信號 96 .mem_cs_n (mem_cs_n ), //DDR2片選信號 97 .mem_cke (mem_cke ), //DDR2時鍾使能信號 98 .mem_addr (mem_addr ), //DDR2地址總線 99 .mem_ba (mem_ba ), //DDR2組地址信號 100 .mem_ras_n (mem_ras_n ), //DDR2行地址選擇信 101 .mem_cas_n (mem_cas_n ), //DDR2列地址選擇信 102 .mem_we_n (mem_we_n ), //DDR2寫使能信號 103 .mem_dm (mem_dm ), //DDR2數據掩膜信號 104 .mem_clk (mem_clk ), //DDR2時鍾信號 105 .mem_clk_n (mem_clk_n ), //DDR2時鍾反相信號 106 .mem_dq (mem_dq ), //DDR2數據總線 107 .mem_dqs (mem_dqs ), //DDR2數據源同步信號 108 .phy_clk (phy_clk ), //DDR2 IP核工作時鍾 109 .reset_phy_clk_n (reset_phy_clk_n ), //DDR2 IP核同步后的復位信號 110 .reset_request_n ( ), //DDR2 IP核復位請求信號 111 .aux_full_rate_clk ( ), //DDR2 IP核全速率時鍾 112 .aux_half_rate_clk ( ) //DDR2 IP核半速率時鍾 113 ); 114 115 //本模塊復位信號 116 assign rst_n = reset_phy_clk_n && local_init_done; 117 //========================================================================== 118 //== 狀態機 119 //========================================================================== 120 always @ (posedge phy_clk or negedge rst_n) begin 121 if(!rst_n) begin 122 burst_wrdone <= 1'b0; 123 burst_rddone <= 1'b0; 124 state <= IDLE; 125 end 126 else begin 127 case(state) 128 //--------------------------------------------------- 空閑 129 IDLE: begin 130 burst_wrdone <= 1'b0; 131 burst_rddone <= 1'b0; 132 if(burst_wrreq && burst_wrlen != `BURST_W'd0) 133 state <= WR_RDY; 134 else if(burst_rdreq && burst_rdlen != `BURST_W'd0) 135 state <= RD_ADDR; 136 else 137 state <= state; 138 end 139 //--------------------------------------------------- 寫准備 140 WR_RDY: begin 141 state <= WR; 142 end 143 //--------------------------------------------------- 寫數據 144 WR: begin 145 if(wraddr_cnt + wrburst_cnt >= wrlen - `BURST_W'd1 && local_ready) begin 146 state <= IDLE; burst_wrdone <= 1'b1; 147 end 148 end 149 //--------------------------------------------------- 讀地址 150 RD_ADDR: begin 151 if(rdaddr_cnt + RDBURST_SIZE >= rdlen && local_ready) begin 152 state <= RD_WAIT; 153 end 154 end 155 //--------------------------------------------------- 讀數據等待 156 RD_WAIT:begin 157 if(rddata_cnt >= rdlen - `BURST_W'h1 && local_rdata_valid) begin 158 state <= IDLE; burst_rddone <= 1'b1; 159 end 160 end 161 default: state <= IDLE; 162 endcase 163 end 164 end 165 //------------------------------------------ 狀態機名稱,測試用 166 reg [55:0] state_name; //1個字符8位寬 167 168 always @(*) begin 169 case(state) 170 IDLE : state_name = "IDLE"; 171 WR_RDY : state_name = "WR_RDY"; 172 WR : state_name = "WR"; 173 RD_ADDR : state_name = "RD_ADDR"; 174 RD_WAIT : state_name = "RD_WAIT"; 175 default : state_name = "IDLE"; 176 endcase 177 end 178 //========================================================================== 179 //== 在進入讀狀態前鎖存讀突發長度 180 //========================================================================== 181 always @ (posedge phy_clk or negedge rst_n) begin 182 if(!rst_n) begin 183 rdlen <= `BURST_W'h0; 184 end 185 else if(state == IDLE && burst_rdreq && burst_rdlen != `BURST_W'd0) begin 186 rdlen <= burst_rdlen; 187 end 188 end 189 190 always @ (posedge phy_clk or negedge rst_n) begin 191 if(!rst_n) begin 192 wrlen <= `BURST_W'h0; 193 end 194 else if(state == IDLE && burst_wrreq && burst_wrlen != `BURST_W'd0) begin 195 wrlen <= burst_wrlen; 196 end 197 end 198 //========================================================================== 199 //== 寫突發的數據計數 200 //========================================================================== 201 always @ (posedge phy_clk or negedge rst_n) begin 202 if(!rst_n) begin 203 wrburst_cnt <= `BURST_W'h0; 204 end 205 else if(state == WR && local_ready) begin 206 if(wrburst_cnt >= WRBURST_SIZE - `BURST_W'h1) 207 wrburst_cnt <= `BURST_W'h0; 208 else 209 wrburst_cnt <= wrburst_cnt + `BURST_W'h1; 210 end 211 end 212 //========================================================================== 213 //== 籌齊2個數據,地址+2 214 //========================================================================== 215 always @ (posedge phy_clk or negedge rst_n) begin 216 if(!rst_n) begin 217 wraddr_cnt <= `BURST_W'h0; 218 end 219 else if(state == WR && local_ready) begin 220 if(wraddr_cnt + wrburst_cnt >= wrlen - `BURST_W'd1) 221 wraddr_cnt <= `BURST_W'h0; 222 else if(wrburst_cnt == WRBURST_SIZE - `BURST_W'h1) 223 wraddr_cnt <= wraddr_cnt + WRBURST_SIZE; 224 end 225 end 226 //========================================================================== 227 //== 每次給出讀指令時,讀地址遞增2 228 //========================================================================== 229 always @ (posedge phy_clk or negedge rst_n) begin 230 if(!rst_n) begin 231 rdaddr_cnt <= `BURST_W'h0; 232 end 233 else if(state == RD_ADDR && local_ready) begin 234 if(rdaddr_cnt >= rdlen - `BURST_W'h1) 235 rdaddr_cnt <= `BURST_W'h0; 236 else 237 rdaddr_cnt <= rdaddr_cnt + RDBURST_SIZE; 238 end 239 end 240 //========================================================================== 241 //== 每讀出一個數據時地址遞增1 242 //========================================================================== 243 always @ (posedge phy_clk or negedge rst_n) begin 244 if(!rst_n) begin 245 rddata_cnt <= `BURST_W'h0; 246 end 247 else if(local_rdata_valid) begin 248 if(rddata_cnt >= rdlen - `BURST_W'h1) 249 rddata_cnt <= `BURST_W'h0; 250 else 251 rddata_cnt <= rddata_cnt + `BURST_W'h1; 252 end 253 end 254 //========================================================================== 255 //== 鎖存local_size並在最后一次讀寫時如果不足突發大小則更改local_size為不足的大小 256 //========================================================================== 257 always @ (posedge phy_clk or negedge rst_n) begin 258 if(!rst_n) begin 259 local_size <= `LOCAL_SIZE_W'h0; 260 end 261 else if(state == IDLE && burst_rdreq && burst_rdlen != `BURST_W'd0) begin 262 local_size <= (burst_rdlen >= RDBURST_SIZE) ? RDBURST_SIZE : burst_rdlen; 263 end 264 else if(state == IDLE && burst_wrreq && burst_wrlen != `BURST_W'd0) begin 265 local_size <= (burst_wrlen >= WRBURST_SIZE) ? WRBURST_SIZE : burst_wrlen; 266 end 267 else if(state == RD_ADDR && rdaddr_cnt + {RDBURST_SIZE[`BURST_W-2:0],1'b0} > rdlen && local_ready) begin 268 local_size <= rdlen - rdaddr_cnt - RDBURST_SIZE; 269 end 270 else if(state == WR && wrburst_cnt == WRBURST_SIZE - `BURST_W'h1 && 271 wraddr_cnt + {WRBURST_SIZE[`BURST_W-2:0],1'b0} > wrlen && local_ready) begin 272 local_size <= wrlen - wraddr_cnt - WRBURST_SIZE; 273 end 274 end 275 //========================================================================== 276 //== 鎖存local_address,並且在完成一次突發讀寫時遞增讀寫地址 277 //========================================================================== 278 always @ (posedge phy_clk or negedge rst_n) begin 279 if(!rst_n) begin 280 local_address <= `LOCAL_ADDR_W'h0; 281 end 282 else if(state == IDLE && burst_wrreq && burst_wrlen != `BURST_W'd0) begin 283 local_address <= burst_wraddr; 284 end 285 else if(state == IDLE && burst_rdreq && burst_rdlen != `BURST_W'd0) begin 286 local_address <= burst_rdaddr; 287 end 288 else if(state == WR && (wrburst_cnt == WRBURST_SIZE - `BURST_W'h1) && local_ready) begin 289 local_address <= local_address + WRBURST_SIZE; 290 end 291 else if(state == RD_ADDR && (rdaddr_cnt + RDBURST_SIZE < rdlen) && local_ready) begin 292 local_address <= local_address + RDBURST_SIZE; 293 end 294 end 295 //========================================================================== 296 //== 其他信號 297 //========================================================================== 298 //讀數據 299 assign burst_rddata = local_rdata; 300 301 //DDR2讀應答,即讀FIFO的寫使能 302 assign burst_rdack = local_rdata_valid; 303 304 //寫數據 305 assign local_wdata = burst_wrdata; 306 307 //DDR2寫應答,即寫FIFO的讀使能 308 assign burst_wrack = (state == WR_RDY || (state == WR && local_ready)) ? 1'b1 : 1'b0; 309 310 //寫請求 311 assign local_write_req = (state == WR) ? 1'b1 : 1'b0; 312 313 //讀請求 314 assign local_read_req = (state == RD_ADDR) ? 1'b1 : 1'b0; 315 316 //burstbegin信號,隨便怎么寫都行 317 assign local_burstbegin = ((state == WR && wrburst_cnt == `BURST_W'h0) || state == RD_ADDR) ? 1'b1 : 1'b0; 318 319 320 endmodule
三、仿真測試
寫突發和讀突發設置為11,寫入 1 到 11 共 11 個數,地址從 1 開始,看看波形是什么樣的。
1 `timescale 1ns/1ns //時間精度 2 `define Clock 10 //時鍾周期 3 `include "DDR2_param.v" 4 5 module DDR2_burst_tb; 6 //========================< 端口 >========================================== 7 //DDR2 IP核接口 ------------------------------------- 8 reg pll_ref_clk ; //DDR2 參考時鍾 9 reg global_reset_n ; //全局復位信號;連接外部復位 10 wire phy_clk ; //DDR2 IP核工作時鍾 11 wire reset_phy_clk_n ; //DDR2 IP核同步后的復位信號 12 wire local_init_done ; //DDR2 IP核初始化完成信號 13 //突發讀寫接口 -------------------------------------- 14 reg burst_rdreq ; //突發讀請求 15 reg burst_wrreq ; //突發寫請求 16 reg [`BURST_W -1:0] burst_rdlen ; //突發讀長度 17 reg [`BURST_W -1:0] burst_wrlen ; //突發寫長度 18 reg [`LOCAL_ADDR_W -1:0] burst_rdaddr ; //突發讀地址 19 reg [`LOCAL_ADDR_W -1:0] burst_wraddr ; //突發寫地址 20 wire [`LOCAL_DATA_W -1:0] burst_rddata ; //突發讀數據 21 reg [`LOCAL_DATA_W -1:0] burst_wrdata ; //突發寫數據 22 wire burst_rdack ; //突發讀應答;連接FIFO 23 wire burst_wrack ; //突發寫應答;連接FIFO 24 wire burst_rddone ; //突發讀完成信號 25 wire burst_wrdone ; //突發寫完成信號 26 //DDR2端口 ------------------------------------------ 27 wire mem_odt ; //DDR2片上終結信號 28 wire mem_cs_n ; //DDR2片選信號 29 wire mem_cke ; //DDR2時鍾使能信號 30 wire [`MEM_ADDR_W -1:0] mem_addr ; //DDR2地址總線 31 wire [`MEM_BANK_W -1:0] mem_ba ; //DDR2BANK信號 32 wire mem_ras_n ; //DDR2行地址選擇信號 33 wire mem_cas_n ; //DDR2列地址選擇信號 34 wire mem_we_n ; //DDR2寫使能信號 35 wire [`MEM_DM_W -1:0] mem_dm ; //DDR2數據掩膜信號 36 wire mem_clk ; //DDR2時鍾信號 37 wire mem_clk_n ; //DDR2時鍾反相信號 38 wire [`MEM_DQ_W -1:0] mem_dq ; //DDR2數據總線 39 wire [`MEM_DQS_W -1:0] mem_dqs ; //DDR2數據源同步信號 40 //========================================================================== 41 //== 模塊例化 42 //========================================================================== 43 DDR2_burst u_DDR2_burst 44 ( 45 //IP核引出接口 ---------------------------------- 46 .pll_ref_clk (pll_ref_clk ), //DDR2 參考時鍾 47 .global_reset_n (global_reset_n ), //全局復位信號,連接外部復位 48 .phy_clk (phy_clk ), //DDR2 IP核工作時鍾 49 .reset_phy_clk_n (reset_phy_clk_n ), //DDR2 IP核同步后的復位信號 50 .local_init_done (local_init_done ), //DDR2 IP核初始化完成信號 51 //突發讀寫接口 ---------------------------------- 52 .burst_rdreq (burst_rdreq ), //突發讀請求 53 .burst_wrreq (burst_wrreq ), //突發寫請求 54 .burst_rdlen (burst_rdlen ), //突發讀長度 55 .burst_wrlen (burst_wrlen ), //突發寫長度 56 .burst_rdaddr (burst_rdaddr ), //突發讀地址 57 .burst_wraddr (burst_wraddr ), //突發寫地址 58 .burst_rddata (burst_rddata ), //突發讀數據 59 .burst_wrdata (burst_wrdata ), //突發寫數據 60 .burst_rdack (burst_rdack ), //突發讀應答,連接FIFO 61 .burst_wrack (burst_wrack ), //突發寫應答,連接FIFO 62 .burst_rddone (burst_rddone ), //突發讀完成信號 63 .burst_wrdone (burst_wrdone ), //突發寫完成信號 64 //芯片接口 -------------------------------------- 65 .mem_odt (mem_odt ), //DDR2片上終結信號 66 .mem_cs_n (mem_cs_n ), //DDR2片選信號 67 .mem_cke (mem_cke ), //DDR2時鍾使能信號 68 .mem_addr (mem_addr ), //DDR2地址總線 69 .mem_ba (mem_ba ), //DDR2bank信號 70 .mem_ras_n (mem_ras_n ), //DDR2行地址選擇信號 71 .mem_cas_n (mem_cas_n ), //DDR2列地址選擇信號 72 .mem_we_n (mem_we_n ), //DDR2寫使能信號 73 .mem_dm (mem_dm ), //DDR2數據掩膜信號 74 .mem_clk (mem_clk ), //DDR2時鍾信號 75 .mem_clk_n (mem_clk_n ), //DDR2時鍾反相信號 76 .mem_dq (mem_dq ), //DDR2數據總線 77 .mem_dqs (mem_dqs ) //DDR2數據源同步信號 78 ); 79 80 DDR2_mem_model mem 81 ( 82 .mem_dq (mem_dq ), 83 .mem_dqs (mem_dqs ), 84 .mem_dqs_n (mem_dqs_n ), 85 .mem_addr (mem_addr ), 86 .mem_ba (mem_ba ), 87 .mem_clk (mem_clk ), 88 .mem_clk_n (mem_clk_n ), 89 .mem_cke (mem_cke ), 90 .mem_cs_n (mem_cs_n ), 91 .mem_ras_n (mem_ras_n ), 92 .mem_cas_n (mem_cas_n ), 93 .mem_we_n (mem_we_n ), 94 .mem_dm (mem_dm ), 95 .mem_odt (mem_odt ) 96 ); 97 //========================================================================== 98 //== 時鍾信號和復位信號 99 //========================================================================== 100 initial begin 101 pll_ref_clk = 1; 102 forever 103 #(`Clock/2) pll_ref_clk = ~pll_ref_clk; 104 end 105 106 initial begin 107 global_reset_n = 0; #(`Clock*20+1); 108 global_reset_n = 1; 109 end 110 //========================================================================== 111 //== 設計輸入信號 112 //========================================================================== 113 initial begin 114 burst_wrreq = 0; 115 burst_rdreq = 0; 116 burst_wrlen = 11; 117 burst_rdlen = 11; 118 burst_wraddr = 0; 119 burst_rdaddr = 0; 120 burst_wrdata = 0; 121 #(`Clock*20+1); 122 //--------------------------------------------------- 第1次 123 @(posedge u_DDR2_burst.rst_n); //初始化完成,復位結束 124 //寫 125 @(posedge phy_clk); 126 burst_wraddr = 1; 127 burst_wrreq = 1; 128 @(posedge phy_clk); 129 burst_wrreq = 0; 130 //讀 131 @(posedge burst_wrdone); 132 @(posedge phy_clk); 133 burst_rdaddr = 1; 134 burst_rdreq = 1; 135 @(posedge phy_clk); 136 burst_rdreq = 0; 137 //--------------------------------------------------- 第2次 138 //寫 139 @(posedge burst_rddone) 140 @(posedge phy_clk); 141 burst_wraddr = 1; 142 burst_wrreq = 1; 143 @(posedge phy_clk); 144 burst_wrreq = 0; 145 //讀 146 @(posedge burst_wrdone); 147 @(posedge phy_clk); 148 burst_rdaddr = 1; 149 burst_rdreq = 1; 150 @(posedge phy_clk); 151 burst_rdreq = 0; 152 end 153 154 //設計寫數據 155 task gen_data; 156 integer i; 157 begin 158 @(posedge burst_wrack); 159 @(posedge phy_clk); 160 161 for(i=1;i<=11;i=i+1) begin 162 burst_wrdata = i; 163 164 @(posedge phy_clk); 165 if(!burst_wrack) 166 i = i-1; 167 end 168 169 end 170 endtask 171 172 initial begin 173 gen_data; 174 gen_data; 175 end 176 177 178 179 endmodule
四、仿真波形
由波形可以看出各個信號的變化過程,上半部分是寫,下半部分是讀。有些信號在末尾會出現別的數字,實際上是廢棄值,並沒有取到。從波形可以看出,數據寫入后又完整的讀出來了,說明本次設計准確無誤。
如果有需要的同學,直接將本模塊復制成一個 DDR2_param.v 文件和 DDR2_burst.v 文件即可使用。如果用不了也沒辦法,反正我的能用。
參考資料:鋯石科技FPGA教程