上一节已经实现了能够顺利的实现队DDR 3 写入16个递增数和把写入的递增数成功地读出来后,那么接下来就是对DDR3芯片的所有地址都进行读写测试,验证FPGA与DDR3芯片的链路是否正常。方法就是通过比较读出来的数据与写入进去的数据进行比较,看是否是一致的。
如上图所示,是DDR的规格说明书。我们用到的型号是MT41J64M16—8Meg x 16 x 8Banks,具体含义是:8Meg 表示含有8M个地址,位宽是16个BIT,8个bank。
计算字节地址:8*8*2=128M字节地址(乘2是因为每个地址可以存放2个字节的数据),一个字节=8个bit
计算字节数据: 8*1024*1024*16=134217728byte
总的突发次数:134217728/16/8=1048576
时序设计图:
各个端口的介绍:
在此实验中,我所设计的是P0端口用来向DDR中写入数据,P1的端口用来读取写入的数据:
p0_wr_en :写入数据的使能信号,
wr_cnt : 对写入的数据的个数计数寄存器,即突发一次写入16个数据,在p0_wr_en 有效时开始进行计数,16个数据后,清零同时p0_wr_en拉低,一次写数据的突发操作完成;
wr_data :写入的数据寄存器,在此仅仅为测试DDR的各个链路的读写是否存在问题,所以写入的数就是从0 开始是递增的一串递增数,写数据寄存器要先于写数据命令到来之前准备好,因为对DDR写入数据时相当于对一个写FIFO进行操作,对于这个FIFO来说就是读取数据,如果没有数据事先准备好的话,会出现读空的现象。
p0_cmd_en:写数据命令使能,当此信号到来的时候,DDR的写数据的相关命令,便开始进行配置;此信号一般在写入数据寄存器的数据准备好后再拉高;
p1_cmd_en:,读数据命令使能,当此信号到来的时候,DDR的读数据的相关命令,便开始进行配置;此信号一般在 p0_cmd_en写命令使能拉高后再拉高;
rd_flag : 读数据的操作标志信号,所有的读数据相关的操作,都在此使能条件下完成,可以看成是读操作的总开关;在写命令拉高后就可以;
rd_cnt: 读操作的计数器,此计数器不仅仅包括了16个数据的读数据突发个数,还包括了,从的安全完成写入数据,到有效读数据的所需要的准备时间;这里的准备时间不同的板子是不一样的,即使板子的时钟是一样的,需要根据仿真时序来一步一步调试;
rd_en: 与p0_wr_en 信号是对应的,此信号的拉高时间周期个数要满足读数据的一次突发个数;即16个
byte_addr:地址位,读数据突发一次是16个数据,每个数据是8字节,所以突发一次16*8=128个地址;
check_data: 校验数据,这里使用来检测与独处的数据是否一致,所以在rd_en 有效的时候进行自加;
burst_cnt:突发次数,需要知道测试一遍要突发多少次,能够与把所有的地址检测完;
error_flag:错误标志位,在chaeck_data与读出来的数据不一致的时候,此标志信号拉高;
error_num: 错误的个数,error_flag信号拉高一次,此信号加一次;
编写代码:
1 module ddr_drive( 2 3 // system signals 4 input sclk , 5 input s_rst_n , 6 // DDR3 User Interfaces 7 output reg p0_cmd_en , 8 output wire [ 2:0] p0_cmd_instr , 9 output wire [ 5:0] p0_cmd_bl , 10 output wire [29:0] p0_byte_addr , 11 output reg p0_wr_en , 12 output wire [ 7:0] p0_wr_mask , 13 output reg [63:0] p0_wr_data , 14 output reg p1_cmd_en , 15 output wire [ 2:0] p1_cmd_instr , 16 output wire [ 5:0] p1_cmd_bl , 17 output reg [29:0] p1_byte_addr , 18 output reg p1_rd_en , 19 input [63:0] p1_rd_data 20 // Debug 21 // input wr_trig 22 ); 23 24 //========================================================================\ 25 // =========== Define Parameter and Internal signals =========== 26 //========================================================================/ 27 localparam RD_END = 'd45 ; 28 29 localparam BURST_NUM_END = 1048575 ; 30 // localparam BURST_NUM_END = 9 ; 31 32 reg [ 3:0] wr_cnt ; 33 reg rd_flag ; 34 reg [ 5:0] rd_cnt ; 35 36 reg [63:0] check_data ; 37 reg [20:0] burst_cnt ; 38 reg error_flag ; 39 reg [15:0] error_num ; 40 41 reg wr_trig ; 42 43 //============================================================================= 44 //************** Main Code ************** 45 //============================================================================= 46 assign p0_cmd_instr = 3'b000; 47 assign p0_cmd_bl = 'd15; 48 assign p0_byte_addr = p1_byte_addr; 49 assign p0_wr_mask = 8'h0; 50 assign p1_cmd_instr = 3'b001; 51 assign p1_cmd_bl = 'd15; 52 53 54 always @(posedge sclk or negedge s_rst_n) begin 55 if(s_rst_n == 1'b0) 56 p0_wr_en <= 1'b0; 57 else if(wr_trig == 1'b1) 58 p0_wr_en <= 1'b1; 59 else if(rd_cnt == RD_END && burst_cnt < BURST_NUM_END) 60 p0_wr_en <= 1'b1; 61 else if(wr_cnt == 'd15) 62 p0_wr_en <= 1'b0; 63 end 64 65 always @(posedge sclk or negedge s_rst_n) begin 66 if(s_rst_n == 1'b0) 67 wr_cnt <= 'd0; 68 else if(p0_wr_en == 1'b1) 69 wr_cnt <= wr_cnt + 1'b1; 70 end 71 72 always @(posedge sclk or negedge s_rst_n) begin 73 if(s_rst_n == 1'b0) 74 p0_wr_data <= 64'h0; 75 else if(p0_wr_en == 1'b1) 76 p0_wr_data <= p0_wr_data + 1'b1; 77 end 78 79 always @(posedge sclk or negedge s_rst_n) begin 80 if(s_rst_n == 1'b0) 81 p0_cmd_en <= 1'b0; 82 else if(wr_cnt == 'd15) 83 p0_cmd_en <= 1'b1; 84 else 85 p0_cmd_en <= 1'b0; 86 end 87 88 //------------------------------------------------------------------ 89 always @(posedge sclk or negedge s_rst_n) begin 90 if(s_rst_n == 1'b0) 91 rd_flag <= 1'b0; 92 else if(rd_cnt == RD_END) 93 rd_flag <= 1'b0; 94 else if(p0_cmd_en == 1'b1) 95 rd_flag <= 1'b1; 96 end 97 98 always @(posedge sclk or negedge s_rst_n) begin 99 if(s_rst_n == 1'b0) 100 p1_cmd_en <= 1'b0; 101 else if(rd_cnt == 'd19) 102 p1_cmd_en <= 1'b1; 103 else 104 p1_cmd_en <= 1'b0; 105 end 106 107 always @(posedge sclk or negedge s_rst_n) begin 108 if(s_rst_n == 1'b0) 109 rd_cnt <= 'd0; 110 else if(rd_flag == 1'b1) 111 rd_cnt <= rd_cnt + 1'b1; 112 else 113 rd_cnt <= 'd0; 114 end 115 116 always @(posedge sclk or negedge s_rst_n) begin 117 if(s_rst_n == 1'b0) 118 p1_rd_en <= 1'b0; 119 else if(rd_cnt == 'd29) 120 p1_rd_en <= 1'b1; 121 else if(rd_cnt == RD_END) 122 p1_rd_en <= 1'b0; 123 end 124 125 always @(posedge sclk or negedge s_rst_n) begin 126 if(s_rst_n == 1'b0) 127 check_data <= 64'h0; 128 else if(p1_rd_en == 1'b1) 129 check_data <= check_data + 1'b1; 130 end 131 132 always @(posedge sclk or negedge s_rst_n) begin 133 if(s_rst_n == 1'b0) 134 p1_byte_addr <= 'd0; 135 else if(p1_cmd_en == 1'b1) 136 p1_byte_addr <= p1_byte_addr + 'd128; 137 else if(wr_trig == 1'b1) 138 p1_byte_addr <= 'd0; 139 end 140 141 always @(posedge sclk or negedge s_rst_n) begin 142 if(s_rst_n == 1'b0) 143 burst_cnt <= 'd0; 144 else if(rd_cnt == RD_END) 145 burst_cnt <= burst_cnt + 1'b1; 146 else if(wr_trig == 1'b1) 147 burst_cnt <= 'd0; 148 end 149 150 always @(posedge sclk or negedge s_rst_n) begin 151 if(s_rst_n == 1'b0) 152 error_flag <= 1'b0; 153 else if(p1_rd_data != check_data && p1_rd_en == 1'b1) 154 error_flag <= 1'b1; 155 else 156 error_flag <= 1'b0; 157 end 158 159 always @(posedge sclk or negedge s_rst_n) begin 160 if(s_rst_n == 1'b0) 161 error_num <= 'd0; 162 else if(error_flag == 1'b1) 163 error_num <= error_num + 1'b1; 164 else if(wr_trig == 1'b1) 165 error_num <= 'd0; 166 end
使用chiop_scop 抓取波形:
1 wire [35:0] CONTROL0 ; 2 wire [35:0] CONTROL1 ; 3 wire [243:0] ila_data ; 4 wire vio_out ; 5 reg vio_out_r1 ; 6 reg vio_out_r2 ; 7 8 assign ila_data[0] = wr_trig; 9 assign ila_data[16:1] = error_num; 10 assign ila_data[17] = error_flag; 11 assign ila_data[18] = p0_cmd_en; 12 assign ila_data[19] = p1_cmd_en; 13 assign ila_data[49:20] = p1_byte_addr; 14 assign ila_data[50] = p0_wr_en; 15 assign ila_data[114:51]= p0_wr_data; 16 assign ila_data[115] = p1_rd_en; 17 assign ila_data[179:116] = p1_rd_data; 18 assign ila_data[243:180] = check_data; 19 20 always @(posedge sclk) begin 21 vio_out_r1 <= vio_out; 22 vio_out_r2 <= vio_out_r1; 23 end 24 25 always @(posedge sclk or negedge s_rst_n) begin 26 if(s_rst_n == 1'b0) 27 wr_trig <= 1'b0; 28 else 29 wr_trig <= vio_out_r2 ^ vio_out_r1; 30 end 31 32 33 chipscope_icon chipscope_icon_inst ( 34 .CONTROL0 (CONTROL0 ),// INOUT BUS [35:0] 35 .CONTROL1 (CONTROL1 )// INOUT BUS [35:0] 36 ); 37 38 39 chipscope_ila chipscope_ila_inst ( 40 .CONTROL (CONTROL0 ), // INOUT BUS [35:0] 41 .CLK (sclk ), // IN 42 .TRIG0 (ila_data )// IN BUS [35:0] 43 ); 44 45 chipscope_vio chipscope_vio_inst ( 46 .CONTROL (CONTROL1 ), // INOUT BUS [35:0] 47 .CLK (sclk ), // IN 48 .SYNC_OUT (vio_out )// OUT BUS [0:0] 49 );
利用上一节写好的tb文件,稍作修改;
1 `timescale 1ps/1ps 2 3 4 module tb_ddr_top ; 5 6 reg ddr3_ref_clk ; 7 reg ddr3_rst_n ; 8 //bebug signals 9 reg wr_trig ; 10 wire c3_calib_done ; 11 12 //ddr3 interface 13 wire [15:0] mcb3_dram_dq ; 14 wire [12:0] mcb3_dram_a ; 15 wire [2:0] mcb3_dram_ba ; 16 wire mcb3_dram_ras_n ; 17 wire mcb3_dram_cas_n ; 18 wire mcb3_dram_we_n ; 19 wire mcb3_dram_odt ; 20 wire mcb3_dram_reset_n ; 21 wire mcb3_dram_cke ; 22 wire mcb3_dram_dm ; 23 wire mcb3_dram_udqs ; 24 wire mcb3_dram_udqs_n ; 25 wire mcb3_rzq ; 26 wire mcb3_zio ; 27 wire mcb3_dram_udm ; 28 wire mcb3_dram_dqs ; 29 wire mcb3_dram_dqs_n ; 30 wire mcb3_dram_ck ; 31 wire mcb3_dram_ck_n ; 32 33 34 35 36 parameter C3_MEMCLK_PERIOD = 20000; 37 38 39 initial begin 40 41 ddr3_ref_clk = 1; 42 ddr3_rst_n = 0; 43 #20000; 44 ddr3_rst_n = 1; 45 46 47 end 48 49 50 51 52 //produce debug signals 53 initial begin 54 wr_trig <= 0; 55 @(posedge c3_calib_done) 56 #100000 57 wr_trig <= 1; 58 #25600 59 wr_trig <= 0; 60 end 61 62 63 64 65 always #(C3_MEMCLK_PERIOD/2) ddr3_ref_clk = ~ddr3_ref_clk ; 66 67 68 ddr_top ddr_top_inst( 69 70 71 72 //sysyterm interface 73 .c3_sys_clk (ddr3_ref_clk ), 74 .c3_sys_rst_i (ddr3_rst_n ), 75 //ddr3 interface 76 .mcb3_dram_dq (mcb3_dram_dq ), 77 .mcb3_dram_a (mcb3_dram_a ), 78 .mcb3_dram_ba (mcb3_dram_ba ), 79 .mcb3_dram_ras_n (mcb3_dram_ras_n ), 80 .mcb3_dram_cas_n (mcb3_dram_cas_n ), 81 .mcb3_dram_we_n (mcb3_dram_we_n ), 82 .mcb3_dram_odt (mcb3_dram_odt ), 83 .mcb3_dram_reset_n (mcb3_dram_reset_n ), 84 .mcb3_dram_cke (mcb3_dram_cke ), 85 .mcb3_dram_dm (mcb3_dram_dm ), 86 .mcb3_dram_udqs (mcb3_dram_udqs ), 87 .mcb3_dram_udqs_n (mcb3_dram_udqs_n ), 88 .mcb3_rzq (mcb3_rzq ), 89 .mcb3_zio (mcb3_zio ), 90 .mcb3_dram_udm (mcb3_dram_udm ), 91 .mcb3_dram_dqs (mcb3_dram_dqs ), 92 .mcb3_dram_dqs_n (mcb3_dram_dqs_n ), 93 .mcb3_dram_ck (mcb3_dram_ck ), 94 .mcb3_dram_ck_n (mcb3_dram_ck_n ), 95 //debug signals 96 .wr_trig (wr_trig) , 97 .c3_calib_done (c3_calib_done) 98 99 ); 100 101 ddr3_model_c3 u_mem_c3( 102 .ck (mcb3_dram_ck), 103 .ck_n (mcb3_dram_ck_n), 104 .cke (mcb3_dram_cke), 105 .cs_n (1'b0), 106 .ras_n (mcb3_dram_ras_n), 107 .cas_n (mcb3_dram_cas_n), 108 .we_n (mcb3_dram_we_n), 109 .dm_tdqs ({mcb3_dram_udm,mcb3_dram_dm}), 110 .ba (mcb3_dram_ba), 111 .addr (mcb3_dram_a), 112 .dq (mcb3_dram_dq), 113 .dqs ({mcb3_dram_udqs,mcb3_dram_dqs}), 114 .dqs_n ({mcb3_dram_udqs_n,mcb3_dram_dqs_n}), 115 .tdqs_n (), 116 .odt (mcb3_dram_odt), 117 .rst_n (mcb3_dram_reset_n) 118 ); 119 120 // The PULLDOWN component is connected to the ZIO signal primarily to avoid the 121 // unknown state in simulation. In real hardware, ZIO should be a no connect(NC) pin. 122 PULLDOWN zio_pulldown3 (.O(zio3)); PULLDOWN rzq_pulldown3 (.O(rzq3)); 123 124 125 126 endmodule
注意:
在进行板级操作之前,我们需要对时钟在进行一些先关操作,我的板载时钟是单口50MHZ,但在先前的仿真过程中和实际操作中DDR3我们设置的是312.5MHZ,在以下路径:F:\STUDAY_FPGA\USB_DDR\usb2.0_read_ddrPN\ise_prj\usb_read\ipcore_dir\mig_39_2\user_design\rtl\mig_39_2.v
localparam C3_CLKFBOUT_MULT = 25; //原来是1
localparam C3_DIVCLK_DIVIDE = 2;//原来是0;
计算公式:312.5/50=12.5
25/2= 12.5
抓取到的波形:
OK完成,有问题加微信交流: