周文強,雷淑嵐,孫維東
(中科芯集成電路有限公司,江蘇無錫 214072)
目前,在服務器、嵌入式片上系統(SoC)芯片中,雙倍速率內存(DDR)得到了廣泛應用,其標準協議也已經發展到了現在的DDR5[1-2]。DDR系統包含DDR控制器、端口物理層(PHY)、DDR同步動態隨機存取內存(SDRAM)3部分[3-4],具有大容量、高速低功耗、低電壓、良好的散熱性等特點[5-6]。因此,在SoC系統芯片中DDR系統起著至關重要的作用。在開啟錯誤檢查與糾正(ECC)功能的DDR系統里,總線上其他各個IP核在讀寫DDR之前,通常需要DDR控制器對DDR SDRAM初始化數據,即需要預先寫入帶有ECC數值的初始數據[7],否則DDR SDRAM中的數據是隨機值,其ECC數值是錯誤的(仿真時是x態),當寫入數據寬度小于DDR memory總寬度時,DDR控制器會做讀-改-寫(RMW)操作[7],先從DDR memory中讀取數據,然后與新寫入的數據合并,接著通過控制器內的ECC算法計算出該數據的ECC值,最后寫入DDR memory。如果不預先初始化數據,在讀取數據的階段,由于DDR memory中初始數據和ECC均為隨機值,當被讀進DDR控制器后,ECC校驗時出現2 bit以上錯誤,實際應用中會使系統不能正常工作,而仿真時則由于出現x態等情況造成仿真進入死循環。而在不支持ECC功能的DDR系統中,則不需要初始化數據,只要先寫后讀即可。
當開啟ECC功能后,在仿真驗證時通常的辦法是通過DDR控制器里的ECC算法計算出對應數據的ECC值,然后將ECC值連同數據一起寫到DDR SDRAM中,這是常用的前門訪問方式。前門訪問方式需要通過控制器發出指令,經過DDR PHY,最后變成DDR SDRAM指令,才能將帶有ECC值的數據寫入DDR SDRAM,對其進行初始化數據操作[7],這消耗了大量的仿真時間。本文針對這個問題,提出了一種自動識別信息并自動計算ECC數值且靈活可配置的后門訪問方法。該方法通過System Verilog語言建立了處理文件,實現了自動讀取配置文件和數據文件的功能,并采用System Verilog語言模擬了與DDR控制器內功能相同的ECC算法(Verilog語言實現),然后處理程序根據讀取的配置信息和數據自動計算出對應數據的ECC值,最后調用DDR SDRAM內的task以后門訪問方式將數據連同ECC值在仿真開始時提前加載到SDRAM中。仿真結果表明,在初始化SDRAM初始數據階段幾乎不需要仿真時間,因而極大地縮短了仿真時間,同時又能達到驗證各IP核讀寫DDR的目的。
常用的SoC系統結構包含中央處理器(CPU)、高速外設、低速外設、總線、DDR子系統等,如圖1所示。其中DDR memory由多個SDRAM顆粒[8-9]構成。CPU發送/接受數據需要經過先進可擴展接口(AXI)總線,然后經過DDR控制器的AXI端口處理后,數據由DDR控制器控制,接著通過DDR PHY接口,傳輸到DDR memory或從DDR memory中讀取數據。

圖1 常用SoC系統芯片結構
本文實驗中采用的DDR系統[7]如圖2所示,該系統包括DDR控制器、DFI標準接口[10]、PHY、DDR SDRAM顆粒,并支持ECC功能。DDR memory由9個DDR3[11]SDRAM顆粒構成,每個SDRAM顆粒數據寬度為8 bit,因此數據總寬度為72 bit,即64 bit數據加8 bit ECC值。

圖2 DDR子系統結構[7]
在AXI總線[12]上其他IP核讀寫DDR之前,必須先對DDR控制器、DDR PHY、SDRAM進行初始化,當開啟ECC功能后,在初始化階段需要預先向SDRAM寫入帶有ECC值的初始數據。如果不初始化數據,則在寫入數據寬度(如32 bit)小于DDR memory總寬度(如64 bit)的情況下,DDR控制器會做RMW操作,即先從DDR memory中讀取數據,然后與新寫入的數據合并(如合并成64 bit),接著通過控制器內的ECC算法計算出合并數據的ECC值,最后將合并數據及ECC值寫入DDR memory,在RMW的讀取階段,由于DDR memory中初始時數據為隨機值,對應的ECC值也是隨機值,這些值被讀進DDR控制器后,ECC校驗時出現2 bit以上錯誤,實際應用中會使系統不能正常工作,而仿真時則由于出現x態等情況造成仿真進入死循環。但是對于不支持ECC功能的DDR子系統,則不需要預先寫入初始數據,只要先寫后讀即可。
本文提出的方法需要建立多個數據文件(load X.dat,X=0,1,2,...)、一個配置文件load.info、一個仿真處理文件ddr_load.sv,用于實現數據處理及ECC計算等功能。
建立的數據文件load X.dat(X=0,1,2,...),格式如下(十六進制):

該文件中的數據就是需要通過后門方式加載到DDR memory中的數據,ECC數值不用手動計算,在處理文件ddr_load.sv中采用System Verilog語言模擬了與控制器功能相同的ECC算法(Verilog語言),當加載數據時算法自動計算對應數據的EC字節數值,最后將數據連同ECC數值一起加載到DDR memory。數據文件的產生方式有2種:1)可以通過編寫腳本,運行后自動產生上述格式的隨機數據或特定數據到load X.dat數據文件中,同時產生配置文件load.info;2)手動建立load X.dat數據文件和load.info配置文件。
本文實驗中用到的是一個load0.dat數據文件,如表1所示。

表1 load0.dat中的數據(十六進制)
驗證中經常有激勵需要訪問多個不同的DDR memory地址段,為提高驗證靈活性,本文提出的方法允許配置多個數據文件(load X.dat,X=0,1,2,...),在配置文件load.info中可配置多個數據文件的信息。配置文件load.info的配置格式為:

load_file_no為數據文件的編號,從0開始編號,第一個文件編號為0(load0.dat),第二個編號為1(load1.dat),依此類推。load_addr為加載的起始地址。load_len為加載的數據長度,以8 bit十六進制數據為一組數據,在數據文件load X.dat總的組數即為數據長度(等同于數據文件load X.dat中的總行數)。
驗證中,根據實際需求,可以靈活配置該文件。本文實驗中用到的配置信息為:

通過System Verilog語言編寫一個ddr_load.sv處理文件,用于初始時以后門方式訪問DDR SDRAM。在該文件中實現自動提取load.info配置文件信息和讀取數據文件load X.dat的功能;同時模擬了設計中的ECC算法,以便在讀取數據文件load X.dat后自動計算出對應數據的ECC數值。步驟如下。
第1步,自動提取配置文件load.info信息。處理流程如圖3所示。


圖3 自動提取配置文件load.info信息
第2步,自動提取數據文件load X.dat信息。部分示例代碼如下。


根據上述代碼規則,表1的數據被暫存到變量load_data中,其格式如圖4所示。
圖4中的DDR memory由9個DDR3 SDRAM顆粒拼接而成,每個SDRAM數據寬度為8 bit,因此總寬度為72 bit(64 bit數據加8 bit ECC值),按照圖4的數據格式,每一行正好為64 bit數據,其中顆粒8的1 Byte數據為每一行64 bit數據對應的ECC數值,這1 Byte數據不需要預先計算,而是由處理文件中的ECC算法根據64 bit數據自動計算得到,最后將64 bit數據連同8 bit ECC數值一起加載到DDR memory中。
第3步,在處理文件中采用System Verilog語言模擬和DDR控制器相同的ECC算法,根據提取的數據,自動計算出對應64 bit數據的ECC數值。部分實例代碼如下:


第4步,調用DDR SDRAM的memory_write()task,將每個64 bit數據及8 bit ECC數值一起以后門方式預先加載到DDR SDRAM顆粒中,如圖5所示。

圖5 通過后門方式自動加載數據和ECC數值
采用C語言編寫一個仿真激勵,該激勵中CPU對DDR3 memory的一小段地址范圍讀寫10次,先寫后讀,讀寫地址范圍為0x10000000~0x10000024,讀寫地址依次遞增(0x1000_0000+4i,i=0,1,2,...,9)。每次讀寫數據位寬為32 bit(0x12345678×i,i=0,1,2,...,9)。本文采用的仿真工具是Synopsys VCS。為了對比結果,在同一臺服務器上,采用相同的激勵在DDR系統開啟ECC功能的條件下,針對以下3種情況,即對DDR3 memory未初始化數據、通過前門訪問初始化數據、通過本文提出的可靈活配置、自動提取信息并計算ECC值的后門訪問方法初始化數據及ECC值分別進行仿真。
當DDR系統開啟ECC功能后,未對DDR3 memory進行初始化數據的仿真結果如圖6和圖7所示。圖6中根據ddr_we_n信號可知,在寫操作之前進行了RWM,控制器先讀取了DDR中的數據,因為未初始化數據,所以為x態,相應DFI接口上讀到的數據也為x態,最后數據被讀進控制器進行RMW的修改和寫操作。

圖6 RMW時DDR3 memory中讀階段
圖7中lane_in為DDR控制器內ECC算法模塊的輸入數據,該數據為RMW操作中modify后,與寫入的32 bit數據合并后的64 bit數據,第一次寫入的32 bit數據是0x00000000。由于讀過來的數據是未初始化的x態,因此經ECC算法模塊計算后ecc_parity全是x態,出現嚴重錯誤,這使得仿真進入死循環。

圖7 控制器內ECC算法計算得到的數據
由于讀寫數據為32 bit,小于DDR3 memory總的64 bit數據位寬,正如本文第2節中所述,由于SDRAM的初始數據和ECC都是隨機值,如圖6所示,仿真為x態,進而在DDR控制器進行RMW操作時,如圖7所示,數據經過ECC模塊校驗時出現嚴重錯誤,導致仿真進入死循環。因此,在DDR系統開啟ECC功能后,必須要先對DDR memory進行初始化數據并計算出ECC值,否則就會使仿真進入死循環。
通過前門訪問初始化DDR memory數據時,需要配置DDR控制器中的寄存器,其中2個數據寄存器用于配置初始化memory的數據,分別為SBRWDATA0(低32 bit)和SBRWDTA1(高32 bit),可隨意配置數據,本實驗中SBRWDATA0配置了0xcccccccc,SBRWDATA1配置了0xdddddddd。初始化數據的地址范圍為0x10000000~0x10000050,初始化數據過程仿真波形如圖8所示,對這段地址的memory全部初始成0xcccccccc_dddddddd,通過前門訪問計算的ECC值為0x03。

圖8 前門訪問初始化數據過程
從仿真結果文件看,整體仿真時間為287449118.5 ps,服務器CPU運行時間為2039.8 s。Verilog代碼編譯時間已不計算在內。激勵向DDR3 memory寫第1筆數據的過程如圖9所示。另外,從圖9中可以看出,激勵在仿真時第一次寫入的數據為0x00000000,寫之前先做RMW操作,從圖中可以看出,先讀取了數據,由于已經通過前門訪問初始化了數據和ECC值,這次讀的數據不再是x態,而是0x03_dddddddd_cccccccc,在RMW后,寫入的數據為0x30_dddddddd_00000000,已經是正確的數據和ECC值了,不會出現4.1節的問題。
文中提出的方法經過仿真后,從仿真log上看,整體仿真時間為265926764.5 ps,服務器CPU運行時間為1729.5 s。后門訪問加載數據的時間幾乎為0。RTL編譯時間已不計算在內。因此,對比前門訪問仿真結果,本文提出的方法在初始化極小一段地址范圍(0x1000_0000~0x1000_0050)時,在服務器CPU運行時間上縮短2039.8 s-1729.5 s=310.3 s,縮短了約15.2%。從中可知,在開啟ECC功能時,如果初始化地址范圍擴大到kB、MB甚至GB數量級時,通過后門訪問初始化數據的方法將節約數小時甚至更多的時間。
圖10是激勵中第一次寫操作時引發RMW的讀階段和寫階段,從中可知,第一次寫入的數據為0x0000_0000,該數據和DDR中初始數據合并成了0xaabbccdd_00000000,其中0xaabbccdd為后門方式初始化后的數據。合并數據的ECC值由控制器內ECC模塊計算,為0xff,最后一起被寫入到DDR memory。另外,該方法也沒有出現4.1節的問題,仿真能正常運行。

圖10 RMW中的read操作和write操作
4.1節至4.3節各仿真結果對比如表2所示。未進行ECC初始化,仿真不能正常運行。在通過前門訪問進行ECC初始化后仿真正常,運行時間為2039.8 s。而通過本文提出的方法,不僅能正常仿真,而且運行時間為1729.5 s,比前門訪問ECC初始化的方法縮短了約15.2%,注意這是在訪問極小一段地址范圍的情況下得出的結果,從中可知,如果訪問地址擴大到kB、MB、GB等情況,本文提出的方法能節省大量時間。

表2 各仿真驗證方法對比結果(極小一段地址空間情況下)
在DDR控制系統開啟ECC功能的情況下,如果訪問的數據寬度小于DDR memory的數據總寬度時,在初始化階段需要對memory數據進行ECC計算并初始化,否則系統不能正常工作。傳統的通過前門訪問初始化數據的方式會占用大量的仿真時間。而本文提出的自動識別配置信息并計算ECC值的后門訪問方法在減少仿真時間方面具有顯著優勢,且配置靈活方便,能夠自動提取信息并采用System Verilog語言模擬ECC算法自動計算出ECC值,在仿真開始時提前將數據和ECC數值加載到DDR memory,同時又能達到相同的驗證目的。在初始化很小一段地址范圍(0x1000_0000~0x1000_0050)時,比前門訪問方式減少約15.2%的時間。從中可知,如果初始化地址范圍擴大到kB、MB、GB的數量級時,采用本文提出的方法將會省下大量的仿真時間、加快研發進度,同時又能達到相同的驗證目的。本文提出的方法適用于各類DDR系統(DDR2~DDR5)。