DDR2(4):对DDR2 IP再次封装
生成 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教程