赞
踩
继上文建立mig ip核后,右键点击生成的IP核,然后选择open ip example design
然后会自动生成一个新工程,点击run simulation
直接进行仿真即可,对波形进行分类如下:
由上图可以看出,当app_cmd[2:0] == 3'd0
时,进入写状态。在写状态,只有当app_en == 1 && app_rdy == 1
时,app_addr
才会递增,这里突发长度是8。
在写状态时,app_wdf_wren
和app_wdf_rdy
必须同时拉高,才可以写进数据。否则数据保持前一个状态不变。
由上图可以看出,只要app_rd_data_valid
拉高,app_rd_data
就会变化,即数据可以被读出。当app_rd_data_valid
拉低时,读出的数据保持之前状态的数据。在此期间,写数据保持不变。
这里是先写入512个数,然后读出512个数,采用写命令与写数据发生在同一时钟周期的模式,比较简单。仿真需要注意:
1.在自己进行仿真时,需要添加官方例程里面的两个文件到自己的工程里,下图所示的ddr3_model_parameter.vh
以及sim_tb_top
里的ddr3_model(ddr3_model.sv)
2.仿真时长最好设置为120us,不然可能等不到init_calib_complete拉高。
3.ui模块的复位是高电平有效,其他都是低电平。
4.app_sr_req,app_ref_req,app_zq_req
需设置为低电平。
`timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 2023/12/12 19:44:49 // Design Name: // Module Name: ddr3_rw // Project Name: // Target Devices: // Tool Versions: // Description: 写进去512个数,读出来512个数 // 采用写命令与写数据发生在同一时钟周期的模式 // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // // module ddr3_rw( input wire ui_clk , input wire ui_clk_sync_rst , input wire init_calib_complete , input wire app_rdy , input wire[127:0] app_rd_data , input wire app_rd_data_end , input wire app_rd_data_valid , input wire app_wdf_rdy , output reg[27:0] app_addr ,//ddr3地址-512个数 output wire[2:0] app_cmd , output wire app_en , output reg[127:0] app_wdf_data , output wire app_wdf_end , output wire app_wdf_wren ); //parameter define parameter DATA_LENGTH = 512; localparam IDLE = 4'b0001; localparam WRITE = 4'b0010; localparam WAIT = 4'b0100; localparam READ = 4'b1000; //wire define wire sys_rst_n; //reg define reg[3:0] cur_state; reg[3:0] next_state; reg[24:0] rd_addr_cnt;//用户读地址计数 reg[24:0] wr_addr_cnt;//用户写地址计数 reg[24:0] rd_cnt;//实际读地址计数 //main code assign sys_rst_n = ~ui_clk_sync_rst; assign app_cmd = (cur_state == READ) ? 1 :0; assign app_en = (cur_state == WRITE && app_rdy && app_wdf_rdy) || (cur_state == READ && app_rdy);//写状态时读写数据和写命令都准备好,读状态时,读命令准备好 assign app_wdf_wren = (cur_state == WRITE) && app_rdy && app_wdf_rdy; assign app_wdf_end = app_wdf_wren;//ddr3芯片和用户时钟分频是4:1,突发长度是8,因此两个信号相等 //fsm always @(posedge ui_clk or negedge sys_rst_n) begin if(~sys_rst_n) begin cur_state <= IDLE; end else cur_state <= next_state; end always @(*)begin if(~sys_rst_n) next_state <= IDLE; else if(init_calib_complete == 1) case(cur_state) IDLE: next_state <= WRITE; WRITE: if(wr_addr_cnt == DATA_LENGTH - 1 && app_rdy == 1 && app_wdf_rdy == 1) next_state <= WAIT; else next_state <= WRITE; WAIT: next_state <= READ; READ: if(rd_addr_cnt == DATA_LENGTH - 1 && app_rdy == 1 ) next_state <= IDLE; else next_state <= READ; default: next_state <= IDLE; endcase end always @(posedge ui_clk or negedge sys_rst_n) begin if(~sys_rst_n) begin app_addr <= 'd0; app_wdf_data <= 'd0; wr_addr_cnt <= 'd0; rd_addr_cnt <= 'd0; end else begin case(cur_state) IDLE:begin app_addr <= 'd0; app_wdf_data <= 'd0; wr_addr_cnt <= 'd0; rd_addr_cnt <= 'd0; end WRITE:begin if(app_rdy && app_wdf_rdy) begin app_addr <= app_addr + 'd8; app_wdf_data <= app_wdf_data + 1'b1; wr_addr_cnt <= wr_addr_cnt + 1'b1; rd_addr_cnt <= 'd0; end else begin app_addr <= app_addr ; app_wdf_data <= app_wdf_data ; wr_addr_cnt <= wr_addr_cnt ; rd_addr_cnt <= 'd0 ; end end WAIT:begin app_addr <= 'd0; app_wdf_data <= app_wdf_data ; wr_addr_cnt <= wr_addr_cnt ; rd_addr_cnt <= rd_addr_cnt ; end READ:begin if(app_rdy) begin//读数据只要读命令有效就会读数据,只有app_rd_data_valid拉高时才表示读出的数据有效 app_addr <= app_addr + 'd8; rd_addr_cnt <= rd_addr_cnt + 1'b1; end else begin app_addr <= app_addr ; rd_addr_cnt <= rd_addr_cnt ; end end default:begin app_addr <= 'd0; rd_addr_cnt <= 'd0; end endcase end end always @(posedge ui_clk or negedge sys_rst_n) begin if(sys_rst_n == 1'b0) begin rd_cnt <= 'd0; end else if(app_rd_data_valid == 1 && rd_cnt == DATA_LENGTH - 1) begin rd_cnt <= 'd0; end else if (app_rd_data_valid) begin rd_cnt <= rd_cnt + 1'b1; end end endmodule
`timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 2023/12/13 17:02:45 // Design Name: // Module Name: ddr3_rw_top // Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // // module ddr3_rw_top( input wire sys_clk , input wire sys_rst_n , input wire[15:0] ddr3_dq ,//input,DDR3数据 input wire[1:0] ddr3_dqs_n ,//input,dqs负 input wire[1:0] ddr3_dqs_p ,//input,dqs正 output wire[13:0] ddr3_addr , output wire[2:0] ddr3_ba , output wire ddr3_ras_n , output wire ddr3_cas_n , output wire ddr3_we_n , output wire ddr3_reset_n , output wire[0:0] ddr3_ck_p , output wire[0:0] ddr3_ck_n , output wire[0:0] ddr3_cke , output wire[0:0] ddr3_cs_n , output wire[1:0] ddr3_dm , output wire[0:0] ddr3_odt ); wire ui_clk; wire ui_clk_sync_rst; wire init_calib_complete; wire app_rdy; wire[127:0] app_rd_data; wire app_rd_data_end ; wire app_rd_data_valid; wire app_wdf_rdy ; wire[27:0] app_addr ; wire[2:0] app_cmd ; wire app_en ; wire[127:0] app_wdf_data; wire app_wdf_end ; wire app_wdf_wren ; wire app_sr_req ; wire app_ref_req ; wire app_zq_req ; wire app_sr_active; wire app_ref_ack ; wire app_zq_ack ; wire[11:0] device_temp ; wire sys_rst ; ddr3_rw inst0( .ui_clk (ui_clk ), .ui_clk_sync_rst (ui_clk_sync_rst ), .init_calib_complete (init_calib_complete ), .app_rdy (app_rdy ), .app_rd_data (app_rd_data ), .app_rd_data_end (app_rd_data_end ), .app_rd_data_valid (app_rd_data_valid ), .app_wdf_rdy (app_wdf_rdy ), .app_addr (app_addr ), .app_cmd (app_cmd ), .app_en (app_en ), .app_wdf_data (app_wdf_data ), .app_wdf_end (app_wdf_end ), .app_wdf_wren (app_wdf_wren ) ); mig_7series_0 inst1( .ddr3_dq (ddr3_dq ), .ddr3_dqs_n (ddr3_dqs_n ), .ddr3_dqs_p (ddr3_dqs_p ), .ddr3_addr (ddr3_addr ), .ddr3_ba (ddr3_ba ), .ddr3_ras_n (ddr3_ras_n ), .ddr3_cas_n (ddr3_cas_n ), .ddr3_we_n (ddr3_we_n ), .ddr3_reset_n (ddr3_reset_n ), .ddr3_ck_p (ddr3_ck_p ), .ddr3_ck_n (ddr3_ck_n ), .ddr3_cke (ddr3_cke ), .ddr3_cs_n (ddr3_cs_n ), .ddr3_dm (ddr3_dm ), .ddr3_odt (ddr3_odt ), .sys_clk_i (clk_200M), .clk_ref_i (clk_200M), .app_addr (app_addr ), .app_cmd (app_cmd ), .app_en (app_en ), .app_wdf_data (app_wdf_data ), .app_wdf_end (app_wdf_end ), .app_wdf_mask (32'b0 ), //need to revise .app_wdf_wren (app_wdf_wren ), .app_rd_data (app_rd_data ), .app_rd_data_end (app_rd_data_end ), .app_rd_data_valid (app_rd_data_valid ), .app_rdy (app_rdy ),//output app_rdy .app_wdf_rdy (app_wdf_rdy ),//output app_wdf_rdy .app_sr_req (1'b0),//input, no need parameter .app_ref_req (1'b0),//input, no need parameter .app_zq_req (1'b0),//input, no need parameter .app_sr_active (app_sr_active),//output,remain no change .app_ref_ack (app_ref_ack),//output,remain no change .app_zq_ack (app_zq_ack),//output,remain no change .ui_clk (ui_clk), .ui_clk_sync_rst (ui_clk_sync_rst), .init_calib_complete (init_calib_complete ), .device_temp (device_temp),//output,remain no change .sys_rst (sys_rst_n) ); clk_wiz_0 inst2 ( // Clock out ports .clk_out1 (clk_200M ), // Status and control signals .resetn (sys_rst_n ), .locked (locked ), // Clock in ports .clk_in1 (sys_clk ) ); endmodule
`timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 2023/12/13 20:06:50 // Design Name: // Module Name: tb_ddr3_rw_top // Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // // module tb_ddr3_rw_top(); reg sys_clk ; reg sys_rst_n ; wire[15:0] ddr3_dq ; wire[1:0] ddr3_dqs_n ; wire[1:0] ddr3_dqs_p ; wire[13:0] ddr3_addr ; wire[2:0] ddr3_ba ; wire ddr3_ras_n ; wire ddr3_cas_n ; wire ddr3_we_n ; wire ddr3_reset_n; wire ddr3_ck_p ; wire ddr3_ck_n ; wire ddr3_cke ; wire ddr3_cs_n ; wire[1:0] ddr3_dm ; wire ddr3_odt ; initial begin sys_clk <= 1'b0; sys_rst_n <= 1'b0; #20 sys_rst_n <= 1'b1; end always #10 sys_clk <= ~sys_clk; ddr3_rw_top uu( .sys_clk (sys_clk ), .sys_rst_n (sys_rst_n ), .ddr3_dq (ddr3_dq ), .ddr3_dqs_n (ddr3_dqs_n ), .ddr3_dqs_p (ddr3_dqs_p ), .ddr3_addr (ddr3_addr ), .ddr3_ba (ddr3_ba ), .ddr3_ras_n (ddr3_ras_n ), .ddr3_cas_n (ddr3_cas_n ), .ddr3_we_n (ddr3_we_n ), .ddr3_reset_n(ddr3_reset_n), .ddr3_ck_p (ddr3_ck_p ), .ddr3_ck_n (ddr3_ck_n ), .ddr3_cke (ddr3_cke ), .ddr3_cs_n (ddr3_cs_n ), .ddr3_dm (ddr3_dm ), .ddr3_odt (ddr3_odt ) ); ddr3_model uu0( .rst_n (sys_rst_n ), .ck (ddr3_ck_p ), .ck_n (ddr3_ck_n ), .cke (ddr3_cke ), .cs_n (ddr3_cs_n ), .ras_n (ddr3_ras_n ), .cas_n (ddr3_cas_n ), .we_n (ddr3_we_n ), .dm_tdqs (ddr3_dm), .ba (ddr3_ba ), .addr (ddr3_addr ), .dq (ddr3_dq), .dqs (ddr3_dqs_p), .dqs_n (ddr3_dqs_n), .tdqs_n ( ), .odt (ddr3_odt ) ); //ddr3_model uu0( // .rst_n (sys_rst_n ), // .ck (ddr3_ck_p ), // .ck_n (ddr3_ck_n ), // .cke (ddr3_cke ), // .cs_n (ddr3_cs_n ), // .ras_n (ddr3_ras_n ), // .cas_n (ddr3_cas_n ), // .we_n (ddr3_we_n ), // .dm_tdqs (ddr3_dm[1:0]), // .ba (ddr3_ba ), // .addr (ddr3_addr ), // .dq (ddr3_dq[15:0]), // .dqs (ddr3_dqs_p[1:0]), // .dqs_n (ddr3_dqs_n[1:0]), // .tdqs_n ( ), // .odt (ddr3_odt ) //); //ddr3_model uu1( // .rst_n (sys_rst_n ), // .ck (ddr3_ck_p ), // .ck_n (ddr3_ck_n ), // .cke (ddr3_cke ), // .cs_n (ddr3_cs_n ), // .ras_n (ddr3_ras_n ), // .cas_n (ddr3_cas_n ), // .we_n (ddr3_we_n ), // .dm_tdqs (ddr3_dm[3:2] ), // .ba (ddr3_ba ), // .addr (ddr3_addr ), // .dq (ddr3_dq[31:16] ), // .dqs (ddr3_dqs_p[3:2] ), // .dqs_n (ddr3_dqs_n[3:2] ), // .tdqs_n ( ), // .odt (ddr3_odt ) //); endmodule
可以看出写了512个数后清零,地址增长到4096后清零,是正确的
可以看到写入读命令一段时间以后,数据才会被读出,读到512个数后停止读。
1.本次实验的mig ip
核的数据位宽设置的是16位,因此在例化ddr3_model
时只例化了一个(ddr3_model
也是16位),如果自己在设置时是16的倍数(32,64等),那么在例化时也需要例化多个ddr3_model
2.在写代码时有错误导致写数据正常,但读不出数据。
上图是错误的,下图是正确的。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。