上一節已經實現了能夠順利的實現隊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完成,有問題加微信交流: