1. 程式人生 > >轉載xilinx-DDR3 ip 核:DDR3除錯總結

轉載xilinx-DDR3 ip 核:DDR3除錯總結

DDR3除錯總結

       以前同是DDR3的無知少年,由於專案需求、工作需要,有幸深入研究DDR3,中間也確實歷經各種盲目階段,查詢資料、建立工程、除錯錯誤等等,如今對此不敢說是精通,也只能說是基本入門,寫此文章的目的也無非是想讓那些和當初的我一樣的初學者少走些彎路而已,也只當是拋磚引玉,也希望大神們能多多指教!提前謝過了,下面也為了不讓大家看的那麼無聊,也會適當換個方式,也望大家能給幾分薄面,大神們多多指點,小菜鳥們就好好學習吧,畢竟也是手打的材料,下面入正題~

      作為初學者,我認為最好能做到以下三個方面:材料準備與學習、工程建立與除錯、日常總結與記錄。

      有些人會問誰都知道要學習資料,你也猜到了我要說手冊,廢話,傻子都知道沒有手冊搞不定的,當然是不只手冊啦,如果你是第一次接觸,最好下載幾篇相關的學術論文,什麼,不知去哪找?!不行就百度,我是在知乎上下的(本人西電,有沒有師姐校友啊,嘿嘿,本校免費下),簡單來說就是下載幾篇相關論文,自己對相關的結構流程能有所瞭解,最好是你要除錯啥就找相關的(我當時就傻x了,調DDR3,下了幾篇DDR2當然可以借鑑,但心裡受影響啊),當然還有最最重要的官方的datasheet,沒有它,想搞定DDR3?洗洗睡吧~當然實驗平臺我就不說了,如果條件簡陋,或者囊中羞澀,軟仿也可以,怎麼?瞧不起軟仿?沒錢想學習還不允許嗎?我當初就硬著頭皮軟仿了一週,可坑爹的實驗室有板子,我愣是不知道,後來才找老師拿了她,於是才上了她,好啦,扯遠了,有板子,板子的原理圖也要有吧,材料這些就可以了,至少你可以有事情幹了!

      再就是建立工程與工程除錯,對於初學者網上都會說先看手冊,建個example,跑一跑,瞭解下例程,對,這一步必須要做,而且要認真做!但是可能等最後你會發現,最終的結果可能並沒有example那麼複雜……,下面再細說,工程除錯是一個很無聊但是很艱鉅的過程,它的重要性,我在這就不說了,覺得不重要的又到睡覺的時候了。

      最後就是日常總結和記錄,像是日記,可並不是,這算是公開的,你師妹想看看?你不給?開玩笑,我一直認為這是個好習慣,日常犯的一些錯誤做好記錄,總結原因和解決辦法,這將會是一筆財富!當然可能沒有過習慣的人,一開始不知該記錄些啥,我一開始也是如此,我就想些啥就寫啥,寫著寫著就知道了,現在不寫都難受,這是病,不過不用治。簡單來說一些實驗現象,或者日常的模擬結果以及分析總結等,可以自己看,哪怕老闆讓你寫報告你也有材料不是?抓緊拾起你的筆,敲起你的鍵盤,跟著我左手右手一個……

      下面到了真刀真槍硬幹的時候了,有本事你別跑!

一、 材料準備與學習

      先簡單介紹下我的準備,而後簡單介紹下DDR3的相關原理性知識,作為專業文件,這部分內容要有,而且必須有!我用的是X家的Virtex-6的FPGA,DDR3用的是美光的,論文下了幾篇,名字我就不列了,自己查去,下面我簡單介紹下DDR3,當然挑和工程相關的,別的自己去查資料。

資料介紹

      算啦,貼張圖,誰讓我勤政愛民呢,重點的已經標出來了,自己動動手指就可以,文件裡有的我就不多說了,自己看,介紹下別的幾個關鍵詞,很有用的!

      DDR(Double Data Rate SDRAM),即雙倍速率同步動態隨機儲存器,含義是資料會被時鐘的上升沿和下降沿取樣,相對於時鐘上升沿取樣,這種方法相當於把取樣時鐘頻率提升了一倍。DDR3 SDRAM在降低系統功耗的同時很大程度上提高了系統性能,其理由“fly-by”和動態片上匹配技術對於訊號完整性的改善效果明顯。

1、邏輯Bank

      組成DDR3的儲存單元稱為邏輯bank,在邏輯bank中,先指定一個行,再指定一個列,可以準確地定位到所需的儲存位置,這是DDR3定址的基本原理,目前,DDR3基本上是8bank設計。

2、物理Bank

      這是一個與儲存子系統相關的術語,並不針對儲存晶片,在PC上的北橋晶片用於控制儲存器與CPU之間的資料交換,為了高效傳輸資料,北橋晶片是儲存器匯流排的資料位寬等同於CPU資料匯流排的位寬,這個位寬被稱為物理Bank(又稱為Rank),當前這個位寬基本為64bit,每個記憶體顆粒的位寬為8bit,為了滿足Rank所需的64位寬,需要8顆記憶體顆粒並行組成。

3、行啟用命令

      在對DDR3的某一個bank內資料進行讀/寫訪問前,首先必須將該bank中資料所在的行啟用,一旦啟用,則該行將保持啟用狀態直到傳送預充電命令到DDR3。傳送行啟用命令式,bank地址與相應的行地址同時發出;行啟用命令傳送後,隨後傳送列地址定址命令與具體的讀/寫操作命令,由於這兩個命令也是同時發出的,所以一般都會以讀/寫命令來表示列定址。從行有效到讀/寫命令發出之間的時間間隔被定義為tRCD,tRCD是DDR的一個重要時序引數,廣義的tRCD以時鐘週期為單位,如tRCD=3,就代表延遲週期為3個時鐘週期。

4、讀/寫命令

      DDR3執行bank的行啟用命令後,可以傳送讀/寫命令對該行進行讀/寫操作,在傳送讀/寫命令時,引腳A10決定是否允許自動預充電操作,如果允許進行預充電,那麼讀/寫命令結束時會自動對該行進行預充電,否則該行將一直保持啟用狀態控制邏輯可繼續對該行進行讀/寫操作

5、資料掩碼

      DDR3採用資料掩碼(DQM)技術,用於遮蔽不需要的資料。通過採用DQM,DDR3控制器能夠以位元組為操作單元指示I/O埠資料的有效性,當然在讀取DDR3時,被掩碼掩掉的資料仍然會從儲存器中讀出,只是在“掩碼邏輯單元”處被遮蔽

6、預充電命令

      資料讀取完成之後,為了釋放DDR3內讀出放大器的空間,以供同位置bank內的其他行定址及傳輸資料,DDR3晶片將執行預充電命令來關閉當前的工作行。預充電對航中所有的儲存單元進行資料重新載入,並對行地址進行復位,其中A10決定是對某一個bank或所有bank進行預充電。預充電命令之後,要經過一段時間才允許傳送行啟用命令操作新的工作行,這個時間間隔稱為tRP

7、重新整理操作

      DDR3需要不斷進行重新整理操作才能在儲存單元中維持資料的有效儲存。雖然預充電能夠針對一個或所有bank中的工作進行重新整理,但是預充電命令與操作相關,不能保證所有儲存空間的遍歷,同時其操作時間也不固定。而重新整理操作則有固定的操作週期,一次對所有行進行操作,以維護儲存單元中的所有資料。但是,與預充電不同,重新整理操作的行是指所有bank中地址相同的行,而預充電中各bank中的工作行地址並不一定是相同的。

      重新整理操作分為兩種:自動重新整理與自重新整理。對於自動重新整理,在重新整理過程中,所有bank都停止工作,而每次重新整理結束後,DDR3才可以進入正常的工作狀態,即在重新整理期間,所有工作指令只能等待而無法執行。自重新整理則主要用於休眠模式低功耗狀態下的資料維護,此時不再以高系統時鐘工作,而是根據內部的時鐘進行重新整理操作。

8、突發長度/型別

      突發是指在同一行中相鄰的儲存單元連續進行資料訪問,連續訪問的時鐘週期數就是突發長度,突發長度由模式暫存器MR0確定,可設定為固定模式:BC4或BL8模式,即在讀/寫操作室通過A12選擇突發長度4或8。進行突發傳輸時,只要指定起始列地址與突發長度,DDR3就會依次地自動對後續相應數量的儲存單元進行讀/寫訪問,而不再需要DDR3控制器連續的提供列地址。在這種模式下,除了第一次資料的訪問需要若干個週期外,後續的每次資料只需一個週期即可獲得

9、模式暫存器

      模式暫存器用於設定DDR3 SDRAM的工作模式,目前支援4個模式暫存器,分別為MR0、MR1、MR2、MR3,其中MR0用於設定DDR3的基本工作模式,包括突發長度、突發型別、CAS延遲和DLL復位等。MR1用來儲存DLL使能、輸出驅動長度、Rtt_Nom、額外長度和寫電平使能等。MR2用來儲存控制更新的特性、Rtt_WR阻抗和CAS寫長度。MR3用來控制MPR。

      Xilinx公司提供的MIG工具適用於高速儲存器介面的解決方案,MIG工具中的DDR3 SDRAM控制器設計執行使用者在V6等器件中通過使用者介面快速建立FPGA內部控制邏輯與外部儲存器的訪問連線,DDR3 SDRAM儲存器介面包括使用者介面模組、儲存控制器、物理層模組、以及本地介面和物理層介面等。

      下面再重申下幾個重要的內容,搞清以下幾個:tRCD(RAS to CAS delay)、CL(CAS Latency,CAS潛伏期/RL,僅在讀取時出現)、CWL(CAS Write Latency)、附加延時AL、BL(Burst Length,DDR3的預取為8bit,所以BL固定為8),BC(DDR3增加了一個4bit Burst Chop 突發突變)。  對與DDR3的工作流程資料裡有,鑑於篇幅原因,就不提了,也該自己看看了。

二、工程建立與除錯

      首先,在CORE Generator中建立一個核。

MIG核

      如果你有引數那很好,按照你的引數建立,如果你沒有晶片資料,但有前輩的測試工程,也可以,在工程目錄下找到datasheet.txt的檔案開啟,裡面有以前建立核的相關配置,當然你如果建立核之後,也會生成這樣一個檔案,配置也都在裡面,如果你啥也沒有,只想跑個模擬,也可以!那就一路預設,或者任意配置,反正又不犯法。

      建好之後,任務就來了,如果你是一個老油條,就不用我多說了,如果你是新手你就按照手冊中建立模擬的過程走一下?算了我告訴你吧,MIG工具最終的生成結果,存放在名為的資料夾中,< component name >資料夾中包含3個資料夾:docs:包含了設計中的相關文件。example_design:在模擬以及硬體測試中均可使用,除了控制器設計外,example_design還包含了可綜合的測試檔案,該測試檔案可生成讀寫命令,並比較邏輯驗證寫入資料與讀取資料的一致性。user_design:中僅包含控制設計,允許使用者根據自身需求設計應用邏輯(測試檔案)。

      想直接分析,可以!把ipcore_dir\ddr3\example_design\rtl下的檔案全部新增到你新建的工程中,還有ipcore_dir\ddr3\example_design\sim目錄下的

tb_ddr3

       當然,你如果習慣用modelsim,可以按照datasheet中的指示進行,我是有點懶,就直接添加了,下面可以簡單配置下頂層引數,可以更快的模擬,將SIM_BYPASS_INIT_CAL設定為FAST,你點了運行了沒?咋還不點?!讓程式跑著,下面說下咱們的工程,example_design中有一個流量生成器,簡單來說就是產生資料,以及最終接收資料給你的,這部分也是使用者可以編輯刪除修改的,也是和user_design的區別,user_design顧名思義,使用者的設計,所以流量生成器當然是自己定義了,別的基本相同,對於 example_design模擬我就不具體分析了,自己看看就可以,我還是說些實用的吧!

       example_design只是讓你能對DDR3的工作有所瞭解,實際中的應用還是要利用user_design,並在此基礎上進行修改,具體的修改等細節的工程問題,在總結中介紹,下面對example_design工程進行一些分析:

這裡寫圖片描述

       資料由流量產生器產生,經過使用者介面部分,儲存器控制部分,物理層部分傳輸給外部DDR3儲存器,資料接收反之,具體每個檔案是幹啥的,看手冊吧。反正我調程式是沒改過Memc_ui_top裡的程式,只是改過頂層的引數。

       下面是user_design中的實現框圖,我們要做的就是建立自己的user_design

這裡寫圖片描述

       你也許會說,一點根據都沒有,怎麼建?還是手冊。

sim

       手冊中還有幾幅時序圖,有BL=4的等等,具體訊號的作用以及輸入輸出關係,因果關係我就不說了,手冊中有訊號線的說明,一看就懂,我們控制的也就是按照這些時序圖來寫,上面的指是一個例子,僅供參考。

三、 日常總結與記錄

       最後這一部分就不像上兩部分那麼枯燥了,下面主要是我日常的總結,主要包括具體的工程實現與模擬分析,以及遇到的問題以及解決方案。此部分含金量很高,我儘量寫的詳細些,大家也認真體會一下。

       引數設定:

       輸入時鐘:125M(此時鐘是外部晶片接的晶振時鐘,內部使用需要進行倍頻分頻)         主時鐘:400M(由輸入時鐘倍頻得到)         突發長度:8(期間用過4,具體原因,下面再說)

下面以一個框圖說明位寬時鐘關係

clk_data_width

       首先以傳送資料為例,使用者端資料首先經過FIFO快取,解決跨時鐘域的問題,FIFO的寫入時鐘為100M,資料位寬為256bit,FIFO的讀取時鐘為200M,位寬為128bit,主時鐘為400M,使用者時鐘為此主時鐘分頻得到,可以驗證資料量:200M*128bit = 400M*2*32bit(其中2為上下沿傳送)。

       接下來對工程進行簡要描述:最一開始資料由一個流量產生器traffic_generator發出,首先對DDR3寫資料,資料每加一,地址加8(突發長度為8,而且貌似規定地址必須加8,我試過4,不成),寫資料地址加到4000時,寫操作結束,開始讀資料,同樣是地址加8,當然讀完4000為止。讀寫資料以及讀寫地址由於是跨時鐘域處理,所以都需要經過FIFO(具體的設定我就不說了,基本設定),也就是4個FIFO,寫資料FIFO,寫地址FIFO,讀資料FIFO,讀地址FIFO,其中兩個地址FIFO是可以IP核覆用的,對於4個FIFO的讀寫將成為此次設計的重點以及難點,我也只能說下大體思路,其餘的就靠大家自己摸索了。

       首先對於寫資料以及寫地址FIFO的寫使能,只要不滿就可以寫,而我們主要控制的就是何時讀,以及如何讀,主要通過狀態機完成,寫資料FIFO的讀使能和使用者介面的寫使能(app_wdf_wren)可以認為同步,我們要控制產生的也即是這幾個訊號:app_wdf_wren,app_wdf_end,wr_dfifo_ren,wr_afifo_ren,決定這幾個訊號的輸入訊號:app_wdf_rdy,app_rdy,wrq(寫請求,不空同時初始化完成就有寫請求)。

       首先對於讀資料以及讀地址FIFO的寫使能,只要地址和資料有效就可以寫,對於讀資料的讀使能,只要FIFO不空就出資料,而我們主要控制的是讀地址FIFO的讀使能,主要通過狀態機完成,我們要控制產生的也即是這幾個訊號:app_en,rd_afifo_ren,決定這幾個訊號的輸入訊號:app_rdy ,rdq。  程式設計完成,最好對DDR3 IP核的引數進行下配置,以方便模擬,可以將SIM_BYPASS_INIT_CAL設定為FAST,可以跳過最一開始的初始化,節約模擬時間,將ORDERING設定為STRICT,中間資料不會進行重排序,便於檢視中間的模擬結果。

       下面就是綜合、實現、生成bit檔案,可以上板子了……

       如果您沒遇到問題,那你真是命好!

       還是說說我這命不好的吧!

問題總結一:系統不能初始化

       一般如果正常新增生成核後自帶的user_design,能正常編譯通過,不會存在不能初始化的問題!!!在此工程中,按照設定總結進行相應設定,進行仔細檢查,利用chipscope進行訊號抓取,可以一個觸發訊號一個觸發訊號的測試,而後分析原因,切不可貿然懷疑硬體的問題(前提是曾經成功過)

問題總結二:雖可以初始化,但是沒有寫入資料

       此問題主要是出現在頂層例化中,初始化訊號未進行模組的正確連線,主要還是不細心,仔細進行頂層檢查,尤其是自己動手修改過的地方,一定要注意!

下面說一下神奇的現象:(寫入資料開始設定為128,最終版為256,改為256可以避免很多問題,可以想想為什麼?)

1、讀寫時鐘改為200M(此時鐘對應於寫FIFO的時鐘,也就是將上面的100M換為200M,ddr3核主時鐘400M),突發長度8(可預知結果出現連續兩個週期數據相同),寫入資料位寬128,讀取位寬128,抓取結果與預測結果相同

sim1

sim2

2、讀寫時鐘改為100M,突發長度4(可預知結果不會出現連續兩個週期數據相同),寫入資料位寬128,讀取位寬128,抓取結果與預測結果相同,看來如果不修改寫入位寬時,突發長度改為4也是一種策略

這裡寫圖片描述

這裡寫圖片描述

這裡寫圖片描述

下面對上面兩種情況進行具體分析:

現象一:此平臺選用的DDR3單片為16位,硬體設計時是將兩片並聯,見下圖

burst_length

       由於寫入的資料為128位,所以如上圖,我們寫入的只是一個大方框的資料,其實為何後面沒有寫入資料的部分又保留了前128位資料的值,這和寫入資料的FIFO的寫使能有關,下面再介紹(先知道此時突發長度為8時前128與後128都寫入相同的資料),接著上面分析,而我們下面現象2時,我們將突發長度改為了4,就可以實現讀出來的資料是一個地址對應一個數據,這是為啥?因為,我們雖然突發長度為4,但是我們程式中地址依舊加的是8,所以結果就是地址加8,我們寫入4個地址的資料(讀也一樣),當然我們讀的時候就像抽取一樣,兩個裡抽一個(畢竟兩個資料是一樣的),那這樣雖然輸出的結果是一樣的,也是正確的,但是這樣就完了嗎?再接著想,這樣一來,我們就相當於浪費了一半的儲存空間!!!!!!你寫入了一半的廢物資料,這樣在實際中是不能容忍的!所以我們要做到的就是將128位資料挨個儲存,不要有重複,避免浪費儲存空間,雖然改突發長度可以得到正確結果,但是代價是顯然的!         前面我提了一下,出現重複資料是因為寫資料FIFO的讀使能存在問題,下面著重解決,首先看兩個圖,上圖是正確的軟仿結果,下圖是導致兩個重複資料的錯誤結果。

modelsim

chipscope_wr_en

       正確的讀使能應該一直為1,而下圖中讀使能呈脈衝式變化,在讀使能為0時就導致資料保持了上一週期的資料,這便是根本原因,既然分析出原因就要修改程式了。

這裡寫圖片描述

       上面中為使app_wdf_wren和wr_dfifo_ren同步特意進行新增,如此解決了連續兩個週期相同資料的問題。但是又出現問題了,給你張圖看下

這裡寫圖片描述

       按道理說寫到502就結束了,後面的哪裡來的呢?

       還記得我之前說過讀資料的地址也是加到4000時結束讀操作,程式中寫的是資料每加一,地址加8,則預設的是8個地址對應一個數據,但是自己進行的是地址加8,對應寫入的是2個數據,所以,對於寫入資料來說,地址雖加到了4000多,但是實際中資料僅僅寫到前2000個地址,而讀資料時,卻讀出來的是4000個地址,但是隻有前2000個地址資料是正確的,後面地址的資料還是儲存的以前寫入的錯誤資料(相鄰兩個週期數據相同),所以會出現上面的情況,所以將讀地址改為原來的一半就可以了!

       最後一個問題就是對於讀寫FIFO的時鐘和位寬最好匹配下,差距不要過大,當然這要取決與你的程式。

       好啦,下面給你最一開始引數的模擬圖。

       將使用者輸入輸出資料位寬256,寫入時鐘100M,app_wdf_data為128,突發長度為8,讀出的資料滿足要求,但是開頭存在些許問題,但其餘無問題,下面為模擬結果,開頭資料存在些許問題,懶得調了,也就放在這了,資料往後打幾拍應該可以解決問題,嘿嘿

這裡寫圖片描述

這裡寫圖片描述

       好啦,打字好累啦,希望這篇文章能對初學者有所幫助,也希望大神們能多多批評指正,先謝過了,大家可以互相交流,覺得有用,大家就點個贊!我也正在除錯一些介面,如果效果好,題主還會繼續更新的,敬請期待!