生成 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教程
来源:oschina
链接:https://my.oschina.net/u/4258318/blog/4470091