設(shè)計(jì)師使用HDL已超過(guò)十年,用它們?nèi)〈谠韴D的設(shè)計(jì)方法并傳達(dá)設(shè)計(jì)理念。 Verilog和VHDL是電子設(shè)計(jì)中使用最廣泛的兩種HDL。 Verilog擁有約35,000名活躍的設(shè)計(jì)師,他們使用Cadence的Verilog軟件套件完成了超過(guò)50,000個(gè)設(shè)計(jì)。
即使Verilog成功,許多經(jīng)驗(yàn)豐富的Verilog用戶仍然認(rèn)為其編程語(yǔ)言界面( PLI)作為“軟件任務(wù)”。一步一步的方法可以幫助您在編寫(xiě)PLI函數(shù)時(shí)“打破僵局”。通過(guò)學(xué)習(xí)PLI設(shè)計(jì)的基本知識(shí)而不會(huì)被太多細(xì)節(jié)困擾,您將獲得可以立即使用的PLI基礎(chǔ)知識(shí)。
為什么要使用PLI?
PLI為Verilog提供了應(yīng)用程序接口(API)。本質(zhì)上,PLI是一種從Verilog代碼調(diào)用C函數(shù)的機(jī)制。人們通常會(huì)調(diào)用在Verilog中調(diào)用PLI例程的構(gòu)造,如果它是模擬器的一部分,則調(diào)用“系統(tǒng)任務(wù)”或“系統(tǒng)函數(shù)”,如果用戶編寫(xiě)它,則調(diào)用“用戶定義的任務(wù)”或“用戶定義的函數(shù)”。由于PLI的基本機(jī)制在兩種情況下都保持不變,因此本文使用術(shù)語(yǔ)“系統(tǒng)調(diào)用”來(lái)表示這兩種結(jié)構(gòu)。大多數(shù)Verilog模擬器包含的常見(jiàn)系統(tǒng)調(diào)用示例是$ display,$ monitor和$ finish。
您使用PLI主要用于執(zhí)行使用Verilog語(yǔ)法無(wú)法執(zhí)行的任務(wù)。例如,IEEE Standard1364-1995 Verilog有一個(gè)用于執(zhí)行文件寫(xiě)入的預(yù)定義構(gòu)造($ fwrite,這是使用PLI編寫(xiě)的另一個(gè)內(nèi)置系統(tǒng)調(diào)用),但它沒(méi)有用于直接從a讀取寄存器值的構(gòu)造。文件(參考文獻(xiàn)2)。更常見(jiàn)的任務(wù)是PLI是實(shí)現(xiàn)預(yù)期結(jié)果的唯一方法,包括編寫(xiě)功能模型,計(jì)算延遲和獲取設(shè)計(jì)信息。 (例如,沒(méi)有Verilog構(gòu)造在設(shè)計(jì)層次結(jié)構(gòu)中給出當(dāng)前模塊的父實(shí)例名稱。)
為了說(shuō)明創(chuàng)建PLI例程的基本步驟,請(qǐng)考慮清單1中的問(wèn)題。問(wèn)題比使用PLI解決的現(xiàn)實(shí)問(wèn)題簡(jiǎn)單得多,但它顯示了許多用于構(gòu)建PLI例程的基本步驟。當(dāng)您在列表中運(yùn)行Verilog時(shí),它應(yīng)該在時(shí)間100打印寄存器的值為10,在時(shí)間300打印3.您可以考慮創(chuàng)建一個(gè)PLI例程作為兩個(gè)步驟:首先,編寫(xiě)PLI例程在C;然后,編譯并將此例程鏈接到模擬器的二進(jìn)制代碼。
編寫(xiě)PLI例程
PLI例程與模擬器接口的方式因模擬器而異,盡管主要功能保持不變。本文討論兩種最流行的商業(yè)模擬器的接口機(jī)制,Cadence的Verilog-XL(參考文獻(xiàn)3)和Synopsys的VCS(參考文獻(xiàn)4)。雖然其他商業(yè)模擬器支持PLI,但它們的接口機(jī)制與這兩者沒(méi)有顯著差異。多年來(lái),Verilog PLI已發(fā)展為PLI 1.0和Verilog程序接口(VPI)(參見(jiàn)側(cè)欄“Verilog PLI的簡(jiǎn)史”)。本文僅涉及PLI 1.0。盡管接口部件和版本存在差異,但您可以將PLI例程的創(chuàng)建分解為四個(gè)主要步驟。
步驟1:包含頭文件
按照慣例,C程序在文件veriuser.c中實(shí)現(xiàn)PLI例程。雖然您可以更改此名稱,但在Verilog-XL環(huán)境中生成編譯腳本時(shí),vconfig工具會(huì)采用此默認(rèn)名稱。現(xiàn)在,假設(shè)您將PLI例程保留在文件veriuser.c中。
在Verilog-XL環(huán)境中,文件veriuser.c必須以以下行開(kāi)頭:
在VCS環(huán)境中,文件必須以:
開(kāi)頭
這些頭文件包含程序?qū)⑹褂玫腣erilog PLI的最基本數(shù)據(jù)結(jié)構(gòu)。
步驟2:聲明函數(shù)原型和變量
PLI例程由幾個(gè)函數(shù)組成。正如您對(duì)普通C程序所做的那樣,您應(yīng)該在函數(shù)定義之前放置函數(shù)的原型聲明。對(duì)于這種情況,函數(shù)顯示為:
在上面的函數(shù)中,int原型聲明意味著這些函數(shù)在它們結(jié)束時(shí)返回一個(gè)整數(shù)執(zhí)行。如果沒(méi)有錯(cuò)誤,則正常返回值為0.但是,如果函數(shù)位于單獨(dú)的文件中,則應(yīng)將它們聲明為外部函數(shù):
與任何其他C程序一樣,典型的PLI例程可能需要一些其他管家變量。
步驟3:設(shè)置基本數(shù)據(jù)結(jié)構(gòu)
您必須定義一個(gè)數(shù)字PLI程序中的數(shù)據(jù)結(jié)構(gòu)。 Verilog模擬器通過(guò)這些變量與C代碼通信。 Open Verilog International(OVI)(www.ovi.org/pubs.html)是一個(gè)標(biāo)準(zhǔn)化Verilog的組織,它只推薦一個(gè)強(qiáng)制數(shù)據(jù)結(jié)構(gòu)veriusertfs。但是,這些數(shù)據(jù)結(jié)構(gòu)的確切數(shù)量和語(yǔ)法因模擬器而異。例如,Verilog-XL需要四個(gè)這樣的數(shù)據(jù)結(jié)構(gòu)及其功能,以便任何PLI例程工作; VCS不需要它們,而是使用單獨(dú)的輸入文件。
Verilog-XL的主要接口數(shù)據(jù)結(jié)構(gòu)是一個(gè)結(jié)構(gòu)數(shù)組或一個(gè)名為veriusertfs的表。 Verilog-XL使用此表來(lái)確定與此PLI例程對(duì)應(yīng)的系統(tǒng)調(diào)用關(guān)聯(lián)的屬性。模擬器無(wú)法識(shí)別除veriusertfs之外的任何名稱。 veriusertfs的每個(gè)元素都有一個(gè)獨(dú)特的函數(shù),你需要所有這些函數(shù)來(lái)實(shí)現(xiàn)正確編寫(xiě)PLI例程的總體目標(biāo)。 veriusertfs中的行數(shù)與用戶定義的系統(tǒng)調(diào)用數(shù)加上最后一個(gè)條目的行數(shù)相同,這是強(qiáng)制性的0.在這種情況下,veriusertfs數(shù)組應(yīng)如下所示:
第一個(gè)條目usertask表示系統(tǒng)調(diào)用沒(méi)有返回任何內(nèi)容。它等同于Pascal中的過(guò)程或函數(shù)返回C中的void。
在前面的數(shù)據(jù)結(jié)構(gòu)中,my_ checktf和my_calltf是用于實(shí)現(xiàn)系統(tǒng)調(diào)用$ print_reg的兩個(gè)函數(shù)的名稱。這些名稱是任意的,您可以用其他名稱替換它們。函數(shù)my_checktf通常稱為checktf例程。它檢查傳遞的參數(shù)的有效性。同樣,my_calltf(通常稱為calltf例程)執(zhí)行系統(tǒng)調(diào)用的主要任務(wù)。這些名稱在veriusertfs中的位置非常重要。例如,如果要將my_checkt用作任何其他名稱作為檢查函數(shù),則它必須是第三個(gè)元素。函數(shù)veriusertfs為您在此例程中不會(huì)使用的一些其他用戶定義函數(shù)提供選項(xiàng)。零替換任何您不使用的函數(shù)。因此,條目中的第二,第四和第六個(gè)元素是零。表1總結(jié)了veriusertfs行中每個(gè)條目的目標(biāo)。如果有其他系統(tǒng)調(diào)用,則需要在veriusertfs中為每個(gè)系統(tǒng)調(diào)用單獨(dú)的條目。
Verilog-XL還需要以下變量或函數(shù):
第一個(gè)變量veriuser_version_str是一個(gè)字符串,表示應(yīng)用程序的用戶定義 - 版本信息。 bool(布爾)變量是一個(gè)整數(shù)子類型,允許值為0和1.在大多數(shù)情況下,您可以使用Cadence為這些變量或函數(shù)提供的默認(rèn)值。
在VCS中,而不是表,您在單獨(dú)的文件中使用等效信息,通常稱為pli.tab。該名稱也是用戶定義的。在使用$ print_reg的當(dāng)前示例中,此文件的內(nèi)容為:
步驟4:組成函數(shù)
原型聲明到位后,您就可以編寫(xiě)兩個(gè)函數(shù)my_checktf()和my_calltf(),它們構(gòu)成了PLI應(yīng)用程序的主體。
如前所述,checktf例程檢查傳遞參數(shù)的有效性。最好檢查參數(shù)總數(shù)是否與預(yù)期相同,以及是否需要每個(gè)參數(shù)。例如,在這種情況下,您希望程序只傳遞一個(gè)類型為register的參數(shù)。您可以在函數(shù)my_checktf()中執(zhí)行此任務(wù)(清單2)。
以tf_開(kāi)頭的函數(shù)是庫(kù)函數(shù),通常稱為實(shí)用程序例程。庫(kù)函數(shù)在前一個(gè)函數(shù)中使用,它們的用法是tf_nump(),它確定傳遞的參數(shù)數(shù)量,以及tf_typep(),它根據(jù)Verilog代碼中系統(tǒng)調(diào)用中的位置確定參數(shù)類型。在這種情況下,系統(tǒng)調(diào)用是$ print_reg。
因此,tf_typep(1)給出第一個(gè)參數(shù)的類型,tf_typep(2)給出第二個(gè)參數(shù)的類型,依此類推。如果參數(shù)不存在,則tf_typep()返回錯(cuò)誤。 (在這種情況下,tf_typep(2)不存在。)在當(dāng)前示例中,您希望程序?qū)⒓拇嫫髦底鳛閰?shù)傳遞。因此,類型應(yīng)該是tf_readwrite。如果導(dǎo)線是預(yù)期參數(shù),則類型應(yīng)為tf_readonly。為了便于錯(cuò)誤條件檢查,最好首先檢查參數(shù)的數(shù)量,然后檢查它們的類型。 tf_error()函數(shù)輸出錯(cuò)誤消息并通知模擬器增加其錯(cuò)誤計(jì)數(shù)。這些庫(kù)函數(shù)和常量是您在步驟1中包含在文件頂部的頭文件的一部分。
calltf函數(shù)是PLI例程的核心。它通常包含PLI例程的主體。在這種情況下,它應(yīng)該讀取寄存器的值,然后打印該值。以下代碼顯示了如何完成此任務(wù):
在上面的代碼中,io_printf()與C中的printf()執(zhí)行相同的工作,在標(biāo)準(zhǔn)輸出中打印值。此外,該函數(shù)在Verilog日志文件中打印相同的信息。函數(shù)tf_getp()獲取寄存器的整數(shù)值。函數(shù)tf_gettime()返回當(dāng)前模擬時(shí)間,不需要輸入?yún)?shù)。 Calltf是PLI例程中最復(fù)雜的函數(shù)。它經(jīng)常運(yùn)行幾百行。
現(xiàn)在你已經(jīng)創(chuàng)建了兩個(gè)主要功能,你需要把它們放在一個(gè)地方。清單3顯示了如何在Verilog-XL環(huán)境中實(shí)現(xiàn)$ print_reg。
接下來(lái)的任務(wù)是讓Verilog模擬器了解新系統(tǒng)調(diào)用的存在。要完成此任務(wù),您必須編譯PLI例程,然后將其鏈接到模擬器的二進(jìn)制文件。雖然您可以通過(guò)運(yùn)行C編譯器并合并目標(biāo)文件來(lái)手動(dòng)將PLI代碼與Verilog二進(jìn)制文件集成,但使用腳本更方便。在Verilog-XL中,一個(gè)名為vconfig的程序會(huì)生成此腳本。此腳本的默認(rèn)名稱是cr_vlog。在生成此腳本時(shí),程序vconfig會(huì)詢問(wèn)您喜歡的已編譯Verilog的名稱。它還詢問(wèn)是否包含來(lái)自標(biāo)準(zhǔn)供應(yīng)商的模型庫(kù),它們是PLI代碼。對(duì)于大多數(shù)這些問(wèn)題,如果您在不輸入任何內(nèi)容的情況下按回車鍵輸入的默認(rèn)答案就足夠了,除非您有自定義環(huán)境。最后,vconfig會(huì)詢問(wèn)您的veriuser.c文件的路徑。一旦生成腳本cr_vlog,您只需要運(yùn)行腳本來(lái)生成可以執(zhí)行新系統(tǒng)調(diào)用的自定義Verilog模擬器。
使用此PLI例程編譯的Verilog示例運(yùn)行生成輸出Verilog-XL模擬器(清單4)。
修改寄存器的值
使用PLI是讀取設(shè)計(jì)信息并在設(shè)計(jì)數(shù)據(jù)庫(kù)中修改此信息。以下示例顯示了如何進(jìn)行此修改。創(chuàng)建系統(tǒng)調(diào)用$ invert,以打印寄存器的值(如上例所示),按位反轉(zhuǎn)內(nèi)容,并打印此更新值。存在許多方法來(lái)反轉(zhuǎn)二進(jìn)制數(shù)的值。通過(guò)使用簡(jiǎn)單的算法進(jìn)行反演,如下面的列表所示,可以幫助您更深入地了解PLI機(jī)制和庫(kù)函數(shù):
將寄存器的內(nèi)容讀取為string;
將字符串中的所有字符串轉(zhuǎn)換為twos,將所有零轉(zhuǎn)換為1,將所有二進(jìn)制轉(zhuǎn)換為零,將所有Z轉(zhuǎn)換為X,并使X保持不變;和
將修改后的字符串放回寄存器。
第二步將所有1轉(zhuǎn)換為零和0。請(qǐng)注意,在這種情況下,checktf函數(shù)與前一個(gè)函數(shù)沒(méi)有區(qū)別,因?yàn)樵谶@兩種情況下輸入?yún)?shù)的數(shù)量和類型都是相同的。
創(chuàng)建PLI例程
列表圖5顯示了VCS環(huán)境中$ invert例程的實(shí)現(xiàn)。該程序使用以下庫(kù)函數(shù):
tf_strgetp()以字符串形式返回寄存器的內(nèi)容。只需liketf_getp(),它將寄存器的內(nèi)容讀作十進(jìn)制。在清單5中,tf_strgetp(1,b)以二進(jìn)制格式讀取第一個(gè)參數(shù)的內(nèi)容。 (h或o代替b,分別以十六進(jìn)制或八進(jìn)制格式讀取)。例程然后將內(nèi)容復(fù)制到字符串val_string。
tf_strdelputp()將值從字符串值規(guī)范寫(xiě)入?yún)?shù)。該函數(shù)有許多參數(shù),包括參數(shù)索引號(hào)(系統(tǒng)調(diào)用中參數(shù)的相對(duì)位置,最左邊的參數(shù)從1開(kāi)始);參數(shù)包含其值的字符串的大小(在這種情況下,它應(yīng)與寄存器的大小相同);編碼基數(shù);實(shí)際的字符串;和另外兩個(gè)與延遲相關(guān)的參數(shù),你可以通過(guò)為它們傳遞零來(lái)忽略它們。雖然在當(dāng)前示例中沒(méi)有顯示,但是tf_strdelputp()的更簡(jiǎn)單的十進(jìn)制對(duì)應(yīng)是tf_putp()。
重要的是要記住程序只能更改或覆蓋來(lái)自PLI例程的某些對(duì)象的值。任何嘗試更改無(wú)法放在Verilog中的過(guò)程賦值左側(cè)的變量(例如連線)都會(huì)導(dǎo)致錯(cuò)誤。通常,您可以修改tf_readwrite類型的變量的內(nèi)容。 checktf函數(shù)my_checktf()檢查此功能。
清單5使用的另一個(gè)用戶定義函數(shù)是move(),它有三個(gè)參數(shù)。在第三個(gè)參數(shù)中,第二個(gè)參數(shù)替換第一個(gè)參數(shù)的每個(gè)匹配項(xiàng)。在當(dāng)前情況下,對(duì)move()的一系列調(diào)用將零更改為1和1更改為零。但是,一旦程序?qū)⒘戕D(zhuǎn)換為1,您必須將字符串中的轉(zhuǎn)換元素與原始元素區(qū)分開(kāi)來(lái)。為了做出這種區(qū)分,程序首先將所有初始的更改為兩個(gè)。二是二進(jìn)制邏輯的無(wú)效值,但您可以在此示例的中間步驟中使用它。最后,程序?qū)⑺袃蓚€(gè)轉(zhuǎn)換為零。程序通過(guò)使用tf_strdelputp()函數(shù)將反轉(zhuǎn)的值放回寄存器來(lái)完成其任務(wù)。
清單6顯示了一個(gè)包含調(diào)用$ invert的Verilog程序示例。在VCS環(huán)境中,文件列出與PLI例程關(guān)聯(lián)的功能。雖然這個(gè)文件可以有任何名稱,但通常稱之為pli.tab。該文件等同于Verilog-XL中的veriusertfs []結(jié)構(gòu)。當(dāng)前示例中此文件的內(nèi)容為:
通過(guò)將此程序保存在test.v文件中,可以生成可執(zhí)行二進(jìn)制文件pli_invert命令:
執(zhí)行pli_invert,你得到:
你現(xiàn)在了解PLI例程的基本結(jié)構(gòu)以及將其鏈接到構(gòu)建Verilog自定義版本的機(jī)制。您還可以通過(guò)PLI例程讀取,轉(zhuǎn)換和修改Verilog中設(shè)計(jì)數(shù)據(jù)庫(kù)的基本組件的值,并讀取例程的模擬時(shí)間。這些任務(wù)是PLI例程執(zhí)行的基本任務(wù),也是最常用的任務(wù)。考慮到PLI提供的所有信息,這些信息只是冰山一角。您還可以使用PLI訪問(wèn)寄存器內(nèi)容以外的設(shè)計(jì)信息。 (有關(guān)Verilog和C建模的更多信息,請(qǐng)參閱參考文獻(xiàn)5和6。)
-
編程
+關(guān)注
關(guān)注
88文章
3628瀏覽量
93819 -
PCB打樣
+關(guān)注
關(guān)注
17文章
2968瀏覽量
21747 -
華強(qiáng)PCB
+關(guān)注
關(guān)注
8文章
1831瀏覽量
27821 -
華強(qiáng)pcb線路板打樣
+關(guān)注
關(guān)注
5文章
14629瀏覽量
43094
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論