主頁 > 軟體設計 > 快速上手Xilinx DDR3 IP核(2)----MIG IP核的官網例程與讀寫測驗模塊(Native介面)

快速上手Xilinx DDR3 IP核(2)----MIG IP核的官網例程與讀寫測驗模塊(Native介面)

2021-12-08 08:20:14 軟體設計

寫在前面

接上一篇文章(配置MIG IP程序):快速上手Xilinx DDR3 IP核(1)----MIG IP核的介紹及配置(Native介面)


1、官方例程(example design)

在我心中,Xilinx是一家完美的公司(自動忽略vivado編譯太慢),技術生態支持實在是做的太好了,Xilinx也知道我們不會用DDR3,所以提供了一個example design給你學習,怎么樣?驚不驚喜?意不意外?(實際上,絕大多數的IP Xilinx都提供了example design~~)

那么接下來就一起學習下官方提供的參考設計唄,

1.1、示例生成步驟

右擊生成的IP核(默認你已經生成了MIG IP核),選擇open IP example design,選擇好路徑后就會生成一個新的工程mig_7series_0_ex,

打開工程mig_7series_0_ex,看下整個工程的結構----2個主要部分:1、MIG IP核;2、讀寫測驗的資料生成模塊

讀寫測驗模塊我們不展開講(太多了,一時半會講不完),我們直接通過波形來學習,

點擊RUN SIMULATION,直接執行仿真(這里可能等幾分鐘(吃電腦配置)----強烈建議使用Modelsim仿真,速度快的不是一星半點

1.2、仿真結果

仿真結果出來后,只保留一些比較有用的信號,并進行分組,如下:

找init_calib_complete拉高后(DDR3初始化完成)的一些區域時序圖,如下圖:

藍線、和黃線處,app_cmd為0,app_en、app_rdy均為高,代表在執行寫命令操作;同時app_wdf_data同地址一致,app_wdf_en、app_wdf_rdy均為高,代表在進行寫資料操作

如下圖:

很多個周期的app_rdy拉低,代表MIG沒有準備好進行寫資料命令,但此時app_wdf_data同地址一致,app_wdf_en、app_wdf_rdy均為高,代表在進行寫資料操作,這正是前面章節提到了寫資料提前與寫命令,因為MIG種有一個FIFO,將要寫入的資料存入FIFO,等到寫命令有效時,再對FIFO進行讀取,這樣做的好處是可以很大程度上做到寫命令和寫資料分離,

如下圖:

藍線處,app_cmd為1,app_en、app_rdy均為高,地址app_addr為0x0000200,代表在執行讀命令操作,經過若干個周期后,黃線處讀取資料有效標志信號app_rd_data_valid拉高,代表成功讀取到了一個資料,資料為0x0000200000020000002000000200,與前面寫入的一致

2、讀寫測驗模塊

通過上節對官方例程的學習,已經初步了解了DDR3的介面時序,接下來就自己撰寫一個簡單的讀寫測驗模塊來對DDR3操作一番,(不當云玩家)

2.1、Verilog代碼

讀寫測驗模塊預期要實作的功能:

  • 寫入一定量的資料(可設定,默認512個)到DDR3,寫入地址從0開始
  • 從地址0開始讀取之前寫入DDR3的資料,同時判斷讀、寫資料是否一致
  • 回圈上兩個步驟,即寫、讀、寫、讀····

不妨先來回顧下DDR3提供的Native介面的時序,

DDR3 的讀或者寫都包含寫命令操作,其中寫操作命令(app_cmd)的值等于 0,讀操作 app_cmd 的值 等于 1,首先來看寫命令時序,如下圖所示,首先檢查 app_rdy,為高則表明此時 IP 核命令接收處于準備好 狀態,可以接收用戶命令,在當前時鐘拉高 app_en,同時發送命令(app_cmd)和地址(app_addr),此時命令和地址被寫入,

寫資料的時序,如下圖所示:

寫資料的情況有3種:

  1. 寫命令與寫資料發生在同一時鐘周期
  2. 寫資料先于寫命令發生(不一定是圖上的一個時鐘周期,因為資料是先寫到了FIFO)發生在同一時鐘周期
  3. 寫資料落后于寫命令發生,但不能超過兩個時鐘周期

結合上圖,寫時序總結如下:首先需要檢查 app_wdf_rdy,該信號為高表明此時 IP 核資料接收處于準備完成狀態,可以接收用戶發過來的資料,在當前時鐘拉高寫使能(app_wdf_wren),給出寫資料 (app_wdf_data),這樣加上發起的寫命令操作就可以成功向 IP 核寫資料,

接著來看讀資料,如下圖所示:

讀時序比較簡單,發出讀命令后,用戶只需等待資料有效信號(app_rd_data_valid)拉高,為高表明此 時資料總線上的資料是有效的回傳資料,需要注意的是,在發出讀命令后,有效讀資料要晚若干周期才出現在資料總線上 (延遲的時間不定),

2.1.1、PLL模塊

本來仿真是不需要PLL模塊的(直接寫時鐘激勵就行),但是考慮到等下還需要上板測驗,而我手頭的開發板主頻50M,MIG的作業時鐘卻是200M,所以需要PLL模塊生成作業時鐘,具體配置略,

2.1.2、DDR3仿真模型

在生成的example design中提供了DDR3的仿真模型,共兩個檔案:

1、DDR3仿真模型的頭檔案

2、DDR3仿真模型

找到這兩個檔案,把它們添加進我們自己的測驗工程里,

2.1.3、讀寫測驗模塊

讀寫測驗模塊生成對MIG IP核的控制時序,并使用一個狀態機來實作回圈寫、讀的程序,狀態機如下:

  • IDLE:初始狀態,等MIG IP核初始化完成后跳轉到寫資料狀態WRITE
  • WRITE:寫資料狀態,在這個狀態向MIG IP核寫入一定量的資料(測驗為512個),當寫入最后一個資料時,同步跳轉到等待狀態WAIT
  • WAIT:過渡狀態,僅維持一個周期
  • READ:讀資料狀態,在這個狀態從MIG IP核讀取一定量的資料(測驗為512個),當讀取最后一個資料時,同步跳轉到初始狀態IDLE,開始新一輪的寫、讀程序

前面說到,DDR3寫資料的時候有3種模式,我們在測驗的時候,固定使用“寫命令與寫資料發生在同一時鐘周期這一模式,這樣一來,代碼撰寫會簡單很多,但相應的會犧牲一點點效率(不會造成多大的影響),

完整的讀寫模塊測驗代碼如下:

//**************************************************************************
// *** 名稱 : ddr3_rw
// *** 作者 : 孤獨的單刀
// *** 博客 : https://blog.csdn.net/wuzhikaidetb
// *** 日期 : 2021.12
// *** 描述 : 對DDR3進行回圈讀寫
//**************************************************************************

//============================< 埠 >======================================
module ddr3_rw #
( 
	parameter	integer					WR_LEN		= 1024		,	//讀、寫長度
	parameter	integer					DATA_WIDTH	= 128		,	//資料位寬,突發長度為8,16bit,共128bit
	parameter	integer					ADDR_WIDTH	= 28			//根據MIG例化而來
)(   
//DDR3相關 ------------------------------------------------------      
    input                   			ui_clk					,	//用戶時鐘
    input                   			ui_clk_sync_rst			,	//復位,高有效
    input                   			init_calib_complete		,	//DDR3初始化完成
//DDR3相關 ------------------------------------------------------	
    input                   			app_rdy					,	//MIG 命令接收準備好標致
    input                   			app_wdf_rdy				,	//MIG資料接收準備好
    input                   			app_rd_data_valid		,	//讀資料有效
    input		[DATA_WIDTH - 1:0]   	app_rd_data				,	//用戶讀資料
    output	reg	[ADDR_WIDTH - 1:0]		app_addr				,	//DDR3地址                      
    output	                			app_en					,	//MIG IP發送命令使能
    output	                			app_wdf_wren			,	//用戶寫資料使能
    output	                			app_wdf_end				,	//突發寫當前時鐘最后一個資料 
    output		[2:0]     				app_cmd					,	//MIG IP核操作命令,讀或者寫
    output	reg	[DATA_WIDTH - 1:0]		app_wdf_data			,	//用戶寫資料
//指示 ----------------------------------------------------------		
    output	reg             			error_flag     	    	   	//讀寫錯誤標志
    );
	
//============================< 信號定義 >======================================
//測驗狀態機-----------------------------------------				
localparam					IDLE	= 4'b0001		;            	//空閑狀態
localparam					WRITE 	= 4'b0010		;            	//寫狀態
localparam					WAIT  	= 4'b0100		;            	//讀到寫過度等待
localparam					READ  	= 4'b1000		;            	//讀狀態
//reg define ----------------------------------------
reg	[3:0]					cur_state				;				//三段式狀態機現態
reg	[3:0]					next_state				;				//三段式狀態機次態
reg	[ADDR_WIDTH - 1:0]		rd_addr_cnt				;				//用戶讀地址計數
reg	[ADDR_WIDTH - 1:0]		wr_addr_cnt				;				//用戶寫地址計數
reg	[ADDR_WIDTH - 1:0]		rd_cnt					;				//實際讀地址標記
//wire define ---------------------------------------										
wire						error					;     			//讀寫錯誤標記
wire						rst_n					;     			//復位,低有效
wire						wr_proc					;				//拉高表示寫程序進行
wire						wr_last					;				//拉高表示寫入最后一個資料
wire						rd_addr_last			;				//拉高表示是最后一個讀地址

 //*********************************************************************************************
//**                    main code
//**********************************************************************************************
//==========================================================================
//==    信號賦值
//==========================================================================  
assign rst_n = ~ui_clk_sync_rst;
//當MIG準備好后,用戶同步準備好
assign app_en = app_rdy && ((cur_state == WRITE && app_wdf_rdy) || cur_state == READ);              
//寫指令,命令接收和資料接收都準備好,此時拉高寫使能
assign app_wdf_wren = (cur_state == WRITE) && wr_proc;
//由于DDR3芯片時鐘和用戶時鐘的分頻選擇4:1,突發長度為8,故兩個信號相同
assign app_wdf_end = app_wdf_wren; 
assign app_cmd = (cur_state == READ) ? 3'd1 :3'd0;					//處于讀的時候命令值為1,其他時候命令值為0	
assign wr_proc = ~app_cmd && app_rdy && app_wdf_rdy;				//拉高表示寫程序進行
//處于寫使能且是最后一個資料
assign wr_last = app_wdf_wren && (wr_addr_cnt == WR_LEN - 1) ;
//處于讀指令、讀有效且是最后一個資料
assign rd_addr_last = (rd_addr_cnt == WR_LEN - 1) && app_rdy && app_cmd;
  
//==========================================================================
//==    狀態機
//==========================================================================    

always @(posedge ui_clk or negedge rst_n) begin
	if(~rst_n)
		cur_state <= IDLE;
	else
		cur_state <= next_state;
end

always @(*) begin
	if(~rst_n)
		next_state = IDLE;
	else
		case(cur_state)
			IDLE:
				if(init_calib_complete)					//MIG IP核初始化完成 
					next_state = WRITE;				
				else				
					next_state = IDLE;				
			WRITE:				
				if(wr_last) 							//寫入最后一個資料
					next_state = WAIT;				
				else				
					next_state = WRITE;							
			WAIT:				
					next_state = READ;				
			READ:				
				if(rd_addr_last) 						//寫入最后一個讀地址,資料讀出需要時間
					next_state = IDLE;
				else
					next_state = READ;					
			default:;
		endcase
end

always @(posedge ui_clk or negedge rst_n) begin
    if(~rst_n) begin				 
        app_wdf_data <= 0;     
        wr_addr_cnt  <= 0;      
        rd_addr_cnt  <= 0;       
        app_addr     <= 0;          
    end
	else
        case(cur_state)
            IDLE:begin
                app_wdf_data <= 0;   
                wr_addr_cnt  <= 0;     
                rd_addr_cnt  <= 0;       
                app_addr     <= 0;
             end
            WRITE:begin
                if(wr_proc)begin   						//寫條件滿足
                    app_wdf_data <= app_wdf_data + 1;  	//寫資料自加
                    wr_addr_cnt  <= wr_addr_cnt + 1;   	//寫地址自加
                    app_addr     <= app_addr + 8;      	//DDR3 地址加8
                end
                else begin                             	//寫條件不滿足,保持當前值
                    app_wdf_data <= app_wdf_data;      
                    wr_addr_cnt  <= wr_addr_cnt;
                    app_addr     <= app_addr; 
                end
              end
            WAIT:begin                                                  
                rd_addr_cnt <= 0;                		//讀地址復位
                app_addr    <= 0;                		//DDR3讀從地址0開始
              end
            READ:begin                               	//讀到設定的地址長度     
                if(app_rdy)begin                  		//若MIG已經準備好,則開始讀
                    rd_addr_cnt <= rd_addr_cnt + 1'd1; 	//用戶地址每次加一
                    app_addr    <= app_addr + 8;       	//DDR3地址加8
                end
                else begin                             	//若MIG沒準備好,則保持原值
                    rd_addr_cnt <= rd_addr_cnt;
                    app_addr    <= app_addr; 
                end
              end
            default:begin
                app_wdf_data <= 0;
                wr_addr_cnt  <= 0;
                rd_addr_cnt  <= 0;
                app_addr     <= 0;
            end
        endcase
end   
//==========================================================================
//==    其他
//==========================================================================

//讀信號有效,且讀出的數不是寫入的數時,將錯誤標志位拉高
assign error = (app_rd_data_valid && (rd_cnt!=app_rd_data));  
                      
//寄存狀態標志位
always @(posedge ui_clk or negedge rst_n) begin
    if(~rst_n) 
        error_flag <= 0;
    else if(error)
        error_flag <= 1;
end
 
//對DDR3實際讀資料個數編號計數
always @(posedge ui_clk or negedge rst_n) begin
    if(~rst_n) 
        rd_cnt <= 0;
	//若計數到讀寫長度,且讀有效,地址計數器則置0   		
    else if(app_rd_data_valid && rd_cnt == WR_LEN - 1)
         rd_cnt <= 0;              
    else if (app_rd_data_valid )	//讀有效情況下每個時鐘+1
        rd_cnt <= rd_cnt + 1;
end
 
endmodule

注釋還是比較詳細的,就不講解了,只說幾個需要注意的點,

  • DDR3的突發長度固定為8,選擇的DDR3芯片為16bit,所以資料位寬 = 8 * 16bit = 128bit
  • DDR3的突發長度固定為8,等于每次操作實際上是對8個地址操作,所以每次寫入資料的地址需要累加8

2.1.4、頂層模塊

頂層模塊的設計十分簡單:只要例化上述3個模塊即可,如下:

//**********************************************************************************
// *** 名稱 : ddr3_rw_top
// *** 作者 : 孤獨的單刀
// *** 博客 : https://blog.csdn.net/wuzhikaidetb
// *** 日期 : 2021.12
// *** 描述 : 頂層模塊----例化DDR3仿真模型與DDR3讀寫測驗模塊,對DDR3進行回圈讀寫測驗
//**********************************************************************************

//============================< 埠 >======================================
module ddr3_rw_top(
//時鐘和復位 ---------------------------
   input              	sys_clk			,         	//系統時鐘
   input              	sys_rst_n		,       	//復位,低有效
//DDR3相關 -----------------------------
   inout	[15:0]		ddr3_dq			,         	//DDR3 資料
   inout	[1:0]		ddr3_dqs_n		,      		//DDR3 dqs負
   inout	[1:0]		ddr3_dqs_p		,      		//DDR3 dqs正       
   output	[13:0]      ddr3_addr		,       	//DDR3 地址
   output	[2:0]       ddr3_ba			,         	//DDR3 banck 選擇
   output	            ddr3_ras_n		,      		//DDR3 行選擇
   output	            ddr3_cas_n		,      		//DDR3 列選擇
   output	            ddr3_we_n		,       	//DDR3 讀寫選擇
   output	            ddr3_reset_n	,    		//DDR3 復位
   output	[0:0]       ddr3_ck_p		,       	//DDR3 時鐘正
   output	[0:0]       ddr3_ck_n		,       	//DDR3 時鐘負
   output	[0:0]       ddr3_cke		,        	//DDR3 時鐘使能
   output	[0:0]       ddr3_cs_n		,       	//DDR3 片選
   output	[1:0]       ddr3_dm			,         	//DDR3_dm
   output	[0:0]       ddr3_odt		,        	//DDR3_odt
//標志相關------------------------------
   output             	error_flag					//錯誤指示信號
);
                
//============================< 信號定義 >======================================                      
//parameter define
parameter	integer		WR_LEN		= 512	;		//讀、寫長度	
parameter	integer		DATA_WIDTH	= 128	;	    //資料位寬,突發長度為8,16bit,共128bit
parameter	integer		ADDR_WIDTH	= 28	;	    //根據MIG例化而來
//wire define  
wire                  	ui_clk				;		//用戶時鐘
wire [ADDR_WIDTH - 1:0]	app_addr			;		//DDR3 地址
wire [2:0]            	app_cmd				;		//用戶讀寫命令
wire                  	app_en				;		//MIG IP核使能
wire                  	app_rdy				;		//MIG IP核空閑
wire [DATA_WIDTH - 1:0]	app_rd_data			;		//用戶讀資料
wire                  	app_rd_data_end		;     	//突發讀當前時鐘最后一個資料 
wire                  	app_rd_data_valid	;   	//讀資料有效
wire [DATA_WIDTH - 1:0]	app_wdf_data		;		//用戶寫資料 
wire                  	app_wdf_end			;		//突發寫當前時鐘最后一個資料 
wire [15:0]           	app_wdf_mask		;		//寫資料屏蔽
wire                  	app_wdf_rdy			;		//寫空閑
wire                  	app_wdf_wren		;		//DDR3 寫使能                  
wire                  	locked				;		//鎖相環頻率穩定標志
wire                  	clk_ref_i			;		//DDR3參考時鐘
wire                  	sys_clk_i			;		//MIG IP核輸入時鐘
wire                  	clk_200				;		//200M時鐘
wire                  	ui_clk_sync_rst		;     	//用戶復位信號
wire                  	init_calib_complete	;		//校準完成信號

//*****************************************************************************************
//**                    main code
//*****************************************************************************************

//============================< 例化DDR3讀寫測驗模塊 >======================================
 ddr3_rw #(
	.WR_LEN							(WR_LEN					),
	.DATA_WIDTH                     (DATA_WIDTH 			),
	.ADDR_WIDTH                     (ADDR_WIDTH 			)
 )
 u_ddr3_rw(
    .ui_clk               			(ui_clk					),                
    .ui_clk_sync_rst      			(ui_clk_sync_rst		),       
    .init_calib_complete  			(init_calib_complete	),
	
    .app_rdy              			(app_rdy				),
    .app_wdf_rdy          			(app_wdf_rdy			),
    .app_rd_data_valid    			(app_rd_data_valid		),
    .app_rd_data          			(app_rd_data			),   
    .app_addr             			(app_addr				),
    .app_en               			(app_en					),
    .app_wdf_wren         			(app_wdf_wren			),
    .app_wdf_end          			(app_wdf_end			),
    .app_cmd              			(app_cmd				),
    .app_wdf_data         			(app_wdf_data			),
   
    .error_flag           			(error_flag				)
    );	
//============================< 例化MIG IP核 >===============================================
mig_7series_0 u_mig_7series_0 (
//DDR3介面-------------------------------------------------
    .ddr3_addr                      (ddr3_addr			),   
    .ddr3_ba                        (ddr3_ba			),     
    .ddr3_cas_n                     (ddr3_cas_n			),  
    .ddr3_ck_n                      (ddr3_ck_n			),   
    .ddr3_ck_p                      (ddr3_ck_p			),   
    .ddr3_cke                       (ddr3_cke			),    
    .ddr3_ras_n                     (ddr3_ras_n			),  
    .ddr3_reset_n                   (ddr3_reset_n		),
    .ddr3_we_n                      (ddr3_we_n			),   
    .ddr3_dq                        (ddr3_dq			),     
    .ddr3_dqs_n                     (ddr3_dqs_n			),  
    .ddr3_dqs_p                     (ddr3_dqs_p			),                                                    
	.ddr3_cs_n                      (ddr3_cs_n			),   
    .ddr3_dm                        (ddr3_dm			),     
    .ddr3_odt                       (ddr3_odt			),
//用戶介面-------------------------------------------------    
    .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		),
    .app_rd_data                    (app_rd_data		), 
    .app_rd_data_end                (app_rd_data_end	),                                                     
    .app_rd_data_valid              (app_rd_data_valid	),  
    .app_wdf_mask                   (31'b0				),                                                    
    .app_rdy                        (app_rdy			), 
    .app_wdf_rdy                    (app_wdf_rdy		), 
    .app_sr_req                     (1'b0				), 
    .app_ref_req                    (1'b0				), 
    .app_zq_req                     (1'b0				), 
    .app_sr_active                  (					),
    .app_ref_ack                    (					),  
    .app_zq_ack                     (					),
//全域信號-------------------------------------------------	
    .ui_clk                         (ui_clk				),       
    .ui_clk_sync_rst                (ui_clk_sync_rst	), 
    .init_calib_complete            (init_calib_complete), 														      
    .sys_clk_i                      (clk_200			),
    .clk_ref_i                      (clk_200			),
    .sys_rst                        (sys_rst_n			)     
);
//============================< 例化PLL模塊 >=============================================== 
clk_wiz_0 u_clk_wiz_0
   (
    .clk_out1						(clk_200			),     	// output clk_out1
    .reset							(1'b0				),		// input resetn
    .locked							(locked				),		// output locked
    .clk_in1						(sys_clk			)		// input clk_in1
);                     

endmodule

2.2、Testbench及仿真結果

好的,Verilog代碼寫完了,接下來就跑跑仿真驗證以下,

2.2.1、Testbench

Testbench也很簡單,只需要提供時鐘、復位激勵;例化讀寫測驗模塊及DDR3仿真模型就好了,如下:

//**************************************************************************
// *** 名稱 : tb_ddr3_rw_top
// *** 作者 : 孤獨的單刀
// *** 博客 : https://blog.csdn.net/wuzhikaidetb
// *** 日期 : 2021.12
// *** 描述 : 對DDR3進行回圈讀寫測驗
//**************************************************************************
`timescale 1ns/100ps

module	tb_ddr3_rw_top();
//============================< 信號 >======================================
//時鐘和復位 --------------------
reg				sys_clk			;				//系統時鐘
reg				sys_rst_n		;				//系統復位
//DDR3相關 ----------------------								
wire [15:0]     ddr3_dq			;				//DDR3 資料
wire [1:0]      ddr3_dqs_n		;				//DDR3 dqs負
wire [1:0]      ddr3_dqs_p		;				//DDR3 dqs正       
wire [13:0]     ddr3_addr		;				//DDR3 地址
wire [2:0]      ddr3_ba			;				//DDR3 banck 選擇
wire            ddr3_ras_n		;				//DDR3 行選擇
wire            ddr3_cas_n		;				//DDR3 列選擇
wire            ddr3_we_n		;				//DDR3 讀寫選擇
wire            ddr3_reset_n	;				//DDR3 復位
wire [0:0]      ddr3_ck_p		;				//DDR3 時鐘正
wire [0:0]      ddr3_ck_n		;				//DDR3 時鐘負
wire [0:0]      ddr3_cke		;				//DDR3 時鐘使能
wire [0:0]      ddr3_cs_n		;				//DDR3 片選
wire [1:0]      ddr3_dm			;				//DDR3_dm
wire [0:0]		ddr3_odt		;				//DDR3_odt
//標志相關-----------------------			
wire			error_flag		;				//讀、寫錯誤標志

//============================< 測驗條件設定 >===============================
//設定初始測驗條件--------------------------------------------------------
initial begin
	sys_clk = 1'b0			;					//初始時鐘為0
	sys_rst_n <= 1'b0		;					//初始復位
	#50											//5個時鐘周期后
	sys_rst_n <= 1'b1		;					//拉高復位,系統進入作業狀態
end
//設定時鐘----------------------------------------------------------------
always #10 sys_clk = ~sys_clk;					//系統時鐘周期20ns


//============================< 被測驗模塊例化 >===============================
//例化DDR3讀寫測驗-------------------
ddr3_rw_top	ddr3_rw_top_inst(
   .sys_clk			(sys_clk		),			//系統時鐘
   .sys_rst_n		(sys_rst_n		),			//復位,低有效
   .ddr3_dq			(ddr3_dq		),			//DDR3 資料
   .ddr3_dqs_n		(ddr3_dqs_n		),      	//DDR3 dqs負
   .ddr3_dqs_p		(ddr3_dqs_p		),      	//DDR3 dqs正       
   .ddr3_addr		(ddr3_addr		),       	//DDR3 地址
   .ddr3_ba			(ddr3_ba		),         	//DDR3 banck 選擇
   .ddr3_ras_n		(ddr3_ras_n		),      	//DDR3 行選擇
   .ddr3_cas_n		(ddr3_cas_n		),      	//DDR3 列選擇
   .ddr3_we_n		(ddr3_we_n		),       	//DDR3 讀寫選擇
   .ddr3_reset_n	(ddr3_reset_n	),    		//DDR3 復位
   .ddr3_ck_p		(ddr3_ck_p		),       	//DDR3 時鐘正
   .ddr3_ck_n		(ddr3_ck_n		),       	//DDR3 時鐘負
   .ddr3_cke		(ddr3_cke		),        	//DDR3 時鐘使能
   .ddr3_cs_n		(ddr3_cs_n		),       	//DDR3 片選
   .ddr3_dm			(ddr3_dm		),         	//DDR3_dm
   .ddr3_odt		(ddr3_odt		),       	//DDR3_odt
   .error_flag		(error_flag		)			//錯誤標志
);   

//例化DDR3模型-----------------------
ddr3_model	ddr3_model_inst
(	
	.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  		(				),			//NULL
	.odt     		(ddr3_odt		)	
);

endmodule

2.2.2、仿真結果

仿真我們不用Vivado跑了(不是說慢,是真慢),改用Modelsim跑,Modelsim跑仿真速度快,來來回回的修改除錯也方便,

廢話少說,仿真結果如下:

上圖中:MIG初始化完成信號init_calib_complete拉高,表示MIG控制器初始化完成,然后,進入開始寫資料,再讀資料,如此不停重復,

上圖是:寫資料程序的開頭部分:

寫入地址從0開始累加,每次累加8,因為突發長度為8;

寫入資料從0開始累加,每次累加1;

當命令有效、寫命令有效,且寫指令為低(代表寫)時,資料被寫入,

上圖是:寫資料程序的結束部分:

寫入地址從0開始累加,每次累加8,因為突發長度為8,到4088截止;

寫入資料從0開始累加,每次累加1,到511截止,共寫入512個資料;

當命令有效、寫命令有效,且寫指令為低(代表寫)時,資料被寫入,

上圖是:讀資料程序的開始部分:

讀取地址從0開始累加,每次累加8,因為突發長度為8;

從發出讀取指令到真正讀到資料需要一定的時間;

當命令有效,且指令為高(代表讀)時,資料被讀出;

讀出的資料與寫入的資料一致(0-1-2-······),

上圖是:讀資料程序的結束部分:

讀取地址從0開始累加,每次累加8,因為突發長度為8,到4088;

從發出讀取指令到真正讀到資料需要一定的時間;

當命令有效,且指令為高(代表讀)時,資料被讀出;

讀出的資料與寫入的資料一致(0-1-2-······511),

3、上板驗證

3.1、驗證環境

FPGA:XC7A35T FGG484-2

DDR3:NT5CB128M16CP-DI

Vivado:Vivado 2019.2

Modelsim:Modelsim SE-64 2020.4

檔案:V1.0

編號:71

3.2、驗證結果

結果基本與仿真結果一致,寫、讀驗證無誤,讀取資料一致,截幾張圖貼出來

初始化完成后進行的寫操作:

讀操作:

至此,讀寫模塊驗證成功,

3、其他

3.1、可能遇到的問題:

3.1.1、Vivado如何聯合modelsim仿真?

使用modelsim仿真xilinx的IP核,主要需要解決仿真庫的問題,不得不說modelsim是真的好用,

供參考:vivado與modelsim的聯合仿真

3.1.2、使用modelsim仿真DDR3報錯Module ‘SIP_PHY_CONTROL‘ is not defined

沒找到什么好辦法,重裝了新版本的modelsim(2020.4版本),重裝以后問題解決,

3.1.3、VIVADO呼叫 ModelSim一直無回應

基本上是語法錯誤,請仔細檢查,

供參考:Xilinx VIVADO 仿真時無法呼叫 ModelSim 失敗的解決辦法

3.1.4、app_rdy信號被拉高一段時間后,然后一直為低的問題

下面三個保留的信號全接到0后解決(Xilinx都在手冊告訴你這么做了,你又不聽,哎······)

3.2、后記

  • 可以看到,Native介面其實相對來講已經很好用了,但是有沒有辦法用起來更方便一點?當然有咯!FIFO用起來方不方便,一個使能信號就能寫資料了,我們接下來就把MIG給封裝成一個FIFO來用,大大簡化作業量,
  • 創作不易,如果本文對您有幫助,還請多多點贊、評論和收藏,您的支持是我持續更新的最大動力!
  • 關于本文,您有什么想法均可在評論區留言交流,如果需要整個工程,請在評論留下郵箱或者私信我郵箱(注意保護隱私),
  • 自身能力不足,如有錯誤還請多多指出!

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/375811.html

標籤:其他

上一篇:NETCore6無法使用DTO更新資料庫記錄

下一篇:配置harbor的nginx反向代理

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more