




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
8.1概述
8.2SystemVerilog程序設計語句
8.3基于SystemVerilog的仿真驗證
8.4SystemVerilog與C語言接口8.1概述8.1.1SystemVerilog語言的發展由OVI(OpenVerilogInternational)和VI(VHDLInternatioanl)兩個國際標準化組織合作成立的Accellera組織一直致力于推出用于系統級芯片設計和驗證的語言。2002年6月,Accellera發布了第一個SystemVerilog語言標準。最初在基于Verilog-2001擴展的開發過程中,新加入的這些語言被稱為“Verilog++”,但最后決定命名為“SystemVerilog3.0”。從名稱可以看出,它不是一種完整的獨立語言,是VerilogHDL的擴展,因而它被認為是Verilog的第三代語言(Verilog-95是第一代,Verilog-2001是第二代)。SystemVerilog3.0在IEEE1364-2001Verilog的基礎上添加了高級的Verilog和“C”數據類型,對于設計和驗證來說,這是向前邁進了重要的一步,同時擴展了Verilog可綜合性語言結構并支持在更高層次上構建硬件模型。2003年5月,Accellera發布SystemVerilog3.1標準,該版本主要是擴展了大量的驗證結構。它添加了C++風格的“類”構造、屬性、繼承,增加了允許約束隨機驗證的功能,有增強的SystemVerilog斷言子集,添加了FunctionalCoverage子集等。Accellera通過與主要的EDA公司密切合作,繼續完善SystemVerilog3.1標準,如Synopsys向SystemVerilog項目提供驗證技術,包括基于Vera、OpenVera斷言的測試臺構造,VCSDirectC模擬C/C++接口,一個覆蓋應用程序的編程接口等。2004年5月,Accellera批準了SystemVerilog的最終草案,并將它命名為SystemVerilog3.1a。2004年6月,Accellera將SystemVerilog3.1a標準提交給IEEE標準協會,希望SystemVerilog作為擴展集添加到下一版本的IEEEVerilog1364標準中。然而,最終IEEEVerilog標準委員會決定不將SystemVerilog合并到Verilog1364標準中,而給它一個新的標準編號1800。2005年11月,IEEE1800-2005SystemVerilog標準正式向公眾發布。2009年,IEEE1800-2005SystemVerilog與IEEE1364-2005Verilog標準合并,作為IEEE1800-2009SystemVerilog標準發布。同時,IEEE終止了舊的Verilog-1364標準,“Verilog”的名稱正式被“SystemVerilog”替代。面對硬件設計和驗證難度的不斷增加,SystemVerilog標準也在不斷發展,以跟上時代的步伐。2012年發布了IEEE1800-2012SystemVerilog標準,增加了設計和驗證增強功能。2017年發布了IEEE1800-2017SystemVerilog標準,此版本并未在2012版標準中添加任何新的語言功能,僅修正了2012版標準中的勘誤表,并增加了對語言語法和語義規則的澄清。表8.1-1列出了SystemVerilog標準發展的主要歷程。8.1.2SystemVerilog語言架構SystemVerilog是一種系統級的硬件描述語言,它建立在VerilogHDL的基礎上,同時結合了VHDL、C/C++以及驗證平臺語言和斷言語言,它是一種多語言的組合。得益于多個EDA公司的捐贈,SystemVerilog語言在VerilogHDL基礎上主要擴展的組件包括:·SUPERLOG擴展合成子集(SUPERLOGESS),來自Co-DesignAutomation公司;·OpenVERA驗證語言,來自Synopsys公司;·PSL斷言,來自IBM公司(最初為Sugar斷言);
·OpenVERAAssertions(OVA),來自Synopsys公司;·VCSDirectC模擬C/C++?接口和覆蓋應用程序編程接口(API),來自Synopsys公司;·獨立編譯和?$readmem擴展,來自Mentor公司;·聯合和高級語言特性,來自BlueSpec公司。上述這些擴展組件和VerilogHDL一起構成了SystemVerilog語言,其架構如圖8.1-1所示,包括在設計和驗證部分的語言擴展。SystemVerilog在設計上有助于編寫可綜合硬件電路的主要擴展包括:(1)封裝通信和協議檢查的接口(interface);(2)增加類似C語言的數據類型(如int型)、用戶自定義數據類型typedef、枚舉類型enum、數據類型轉換等;(3)結構體(struct)和聯合體(union);(4)可被多個設計塊共享的定義包(package);(5)增加類似C語言的運算符及賦值操作符,如++、--、+=等;(6)顯示過程塊;(7)優先級(priority)和唯一(unique)修飾符;(8)增加過程語句,如do-while、arrayassignments等。SystemVerilog在驗證方面擴展的子集主要包括:(1)產生測試激勵、驅動、響應及監控等;(2)斷言子集(assertions):先進的驗證語言用于形式和半形式驗證,檢查來自DUT的組合/順序邏輯響應;(3)功能覆蓋子集:測量設計的功能覆蓋率;(4)?C和C++?仿真接口(DirectProgrammingInterface,DPI)及覆蓋率應用程序編程接口(API):直接用于C/C++?連接及AssertionAPI和CoverageAPI。相對于VerilogHDL在寄存器級、邏輯級、門級設計上的優勢,SystemVerilog更適合于可重用可綜合IP和可重用驗證IP設計,以及特大型基于IP的系統級設計和驗證。同時,它和芯片驗證方法學(如UVM)相結合,可作為實現方法學的一種語言工具,從而大大增強模塊復用性,提高芯片開發效率,縮短開發周期。8.2SystemVerilog程序設計語句8.2.1數據類型設計中常用的數據類型是整型。除了VerilogHDL已有的整型類型wire、reg和interger外,SystemVerilog從VHDL和C/C++語言中引入logic、int等數據類型,具體如表8.2-1所示。在VerilogHDL中,數值可取值0、1、x和z,四態數據主要面向RTL綜合,其中z值被用來表示無連接或三態設計邏輯,x值有助于檢測多驅動設計錯誤。但在更高級別的抽象建模中,如系統和事務級別,邏輯值z和x很少用到,因此SystemVerilog定義了雙態數據類型,即只能取0或1值。相對于四態數據,雙態數據有利于加快仿真速度并減少內存的使用。同時,這些類似C語言的雙態數據可用于C/C++?的接口。SystemVerilog的DPI可將Verilog模型轉換為C或C++?模型;使用具有共同類型的數據,可以簡單而高效地在兩種語言之間來回傳遞數據。logic類型是SystemVerilog中最常用的數據類型,下面就重點介紹logic類型的語義。SystemVerilog中的logic類型是變量類型,是對reg類型的擴展。它既可以作為寄存器類型在過程塊中被賦值,也可以用在連續賦值語句和結構描述中作為網線類型使用。在例8.2-1的VerilogHDL描述的模塊test(圖8.2-1)中,信號線atob連接了u1模塊的輸出端out和u2模塊的輸入端in。在實際的物理電路中,atob、u1.out和u2.in是同一個信號,但由于它們處于不同模塊的不同端口或其不同的賦值方式,導致數據類型不同。在SystemVerilog描述中,信號atob、u1.out和u2.in都可用logic來定義,保證了同一個信號在模塊內部、模塊外部和測試平臺中的一致性;它使得在任何抽象層次上建模都更加容易。除了常用的整型數據類型外,SystemVerilog還定義了實型數據類型,包括real類型(類似C語言中的double類型)、shortreal類型(類似C語言中的float類型)、realtime類型以及字符串類型(string)、靜態變量(static)等。SystemVerilog在基本數據類型的基礎上,引入C/C++語言中構造類型的概念,設計了數組(array)、自定義(typedef)、枚舉(enum)、結構體(struct)和聯合體(union)等靈活多樣的數據類型,以滿足不同抽象層次的建模。1.數組(array)在VerilogHDL中學習了數組類型的定義及賦值,如“reg[7:0]mem[1:256];”。Verilog中對數組不能整體訪問,必須使用數組名加上一個或多個索引地址的方式訪問數組中的每個元素。在SystemVerilog中同樣定義了數組,但將數組分成合并數組和非合并數組兩大類。(1)合并數組(packedarray),在數組名前聲明數組的大小。(2)非合并數組(unpackedarray),在數組名后聲明數組的大小。2.自定義(typedef)VerilogHDL不允許用戶定義新的數據類型,SystemVerilog則通過使用typedef提供了一種方法來定義新的數據類型。其語法為typedefexisting_typemytype_t;3.枚舉(enum)指令操作碼或狀態機中用VerilogHDL宏定義或參數定義來取代常數,以提高代碼可讀性及維護性,但是需要單獨對每一個常數定義其對應的宏名或參數名。SystemVerilog引入C/C++語言中的枚舉類型,可以自動為列表中的每個名稱分配不同的數值。其基本語法為enumdata_type{enum_name0,enum_name1,…}變量名4.結構體(struct)同C/C++類似,如果在設計中不同類型的變量具有邏輯關聯性,如接口協議中既有控制信號,又有地址和數據總線,這時可利用結構體將這些變量組合在一起并賦予一個共同的名稱。5.聯合體(union)同C/C++類似,聯合體和結構體的區別在于任何一個時間內只存在一個聯合體成員,所以聯合體變量所占位數由最大位寬成員決定。8.2.2操作符VerilogHDL提供了很多運算符用于算術運算、邏輯判斷及位操作等。SystemVerilog在此基礎上新增加了一些操作符,以方便更高層次的建模,見表8.2-2。SystemVerilog還增加了C/C++語言中的強制類型轉換功能,通過使用casting操作符“'”將變量數據類型、數據寬度及數據符號強制轉換成任意類型,很好地解決了變量類型或位寬不一致的錯誤。8.2.3模塊的定義及調用在VerilogHDL中,連接到模塊端口的數據類型被限制為線網類型以及變量類型中的reg、integer類型。在SystemVerilog中則去除了這種限制,任何數據類型都可以通過端口傳遞,包括實數、數組和結構體。在VerilogHDL結構調用語句中,若使用名稱對應法,則要寫明信號線和其連接的端口。SystemVerilog提供了調用語句的兩種簡化方式,如果信號名和端口名一樣,則可省略信號名。更加簡化的形式是“.*”,表示除了明確給出端口連接關系的,剩下的所有端口和與之連接的信號名字一樣。在模塊定義時使用參數可提高模塊的可配置性及重復使用率,SystemVerilog在傳統parameter基礎上擴展,將數據類型參數化,8.2.4過程塊在VerilogHDL中使用always過程塊進行電路設計,仿真工具或綜合工具通過解析代碼來“推斷”或“猜測”always過程塊設計的是組合邏輯、latch,還是時序邏輯。不同EDA工具的“推斷”結果可能會不一樣,比如在組合電路設計中由于編程錯誤產生不需要的latch,這種錯誤在綜合后才能發現,從而導致功能仿真和綜合后的時序仿真結果不一致。為了明確always過程塊設計的電路類型,SystemVerilog增加了三種always過程塊:always_comb(組合邏輯)、always_latch(latch塊)和always_ff(時序邏輯)。這樣EDA工具就不需要“推斷”設計者的意圖,同時當這些過程塊的內容與該類型邏輯不匹配時,EDA工具就發出警告。
1.always_comb過程塊always_comb表明設計的電路是組合邏輯。2.always_latch過程塊always_latch類似always_comb,EDA工具會自動推導出完整的事件敏感列表。但always_latch明確指出這個過程塊是基于latch的邏輯,因此會檢查內部語句是否滿足latch特點。3.always_ff過程塊always_ff表明設計的是一個時序電路。8.2.5分支語句在VerilogHDL中用于RTL建模的高級程序語句主要是if-else和case,如果沒有遵循嚴格的編碼風格,則它們會產生優先級的選擇結構或分支的非唯一性。在case語句中如果沒有正確使用full_case和parallel_case綜合指令,還會引起一些其他的錯誤。SystemVerilog中對分支語句進行了功能增強,如在if或case關鍵字之前使用唯一性(unique)和優先級(priority)決策修飾符,從而明確了分支是否唯一,或者結構是否具有優先級。1.if-else語句增強SystemVerilog中增加了unique或priority關鍵字用于if-else語句,以減少EDA工具決策的模糊性,并可以在早期設計階段就發現潛在的設計錯誤。
在圖8.2-2中,首先用傳統的if-else語句設計一個多路選擇器,如代碼a所示,EDA工具產生優先級的選擇電路。對于這個選擇器,優先級的順序并不重要,只是設計者在代碼編寫中碰巧列出了這樣的邏輯順序,因此在if前加上unique修飾符表示每個分支是唯一的,這樣EDA工具可以優化出并行的電路結構,如代碼b所示。若在uniqueif中出現多個分支同時滿足的情況,如代碼c所示,則在編譯或仿真階段會報警。同時利用uniqueif還可以檢查是否產生了不需要的latch。對代碼b,當sel等于1、2、4以外的其他數據時,沒有一個分支條件滿足,因此對out沒有賦值更新,這時會產生latch,保持原值不變,EDA工具報警。
相對于unique代表各分支是獨立的,結構上是并行的,關鍵字priority明確表示if-else具有優先級。當有多分支條件滿足時,選擇優先級高的分支完成相應的賦值操作。2.case語句增強修飾符unique和priority也可用在case/casez/casex語句中,作為并行或優先級結構的指示。使用uniquecase結構時,EDA工具同樣檢查每個分支是否相互獨立,即沒有多個分支條件同時滿足的情況。在圖8.2-3的代碼a中,使用casez語句允許出現無關位或屏蔽位,這樣可以簡化譯碼電路,但是當request信號的位中出現多個“1”時,多個分支判斷同時成立。仿真工具對這個潛在問題不會告警,綜合工具可能會發現但沒有辦法判斷設計者的真實意圖。在代碼b中使用了uniquecase語句,明確告訴EDA工具case中的分支應該是獨立并行的,不能多個分支同時成立,這樣在語句執行時如果不滿足unique要求就會發出警告。使用priority修飾符允許多個分支同時成立,這時執行第一個滿足要求的分支語句,如代碼c中優先級最高的是slave1_grant分支。與if-else語句類似,在always_comb塊中使用上述兩種case結構可以檢測不需要的latch。對于case語句,綜合工具雖然也提供了綜合指令parallel_case和full_case,但這可能會導致RTL級功能仿真和綜合后的門級仿真不一致。SystemVerilog語言新增的unique和priority修飾符是語言的一部分,它們會被所有仿真工具、綜合工具、形式驗證工具等支持并按統一的規則檢查,確保了工具之間的一致性。8.2.6循環語句VerilogHDL支持的循環語句有for、repeat和while,SystemVerilog中增強了for語句的功能,同時又增加了新的循環用于RTL建模。1.for語句借鑒C語言中for的用法,SystemVerilog在傳統的for語句中增加了語句內定義循環控制變量數據類型,對多個變量賦初值,有多條賦值語句,如下面代碼。注意,for內部定義的變量i是一個局部變量,只能在循環體內使用。for(inti=0;i<=15;i++)... //局部變量ifor(inti=0,j=15;j>0;i++,j--)... //多個循環控制變量2.do-while循環SystemVerilog增加了C語言中的do-while循環,即先執行后判斷。與while的區別是,do-while至少會執行一次循環體。3.跳轉語句VerilogHDL提供disable語句控制代碼的執行,可以中斷正在執行的語句塊或任務。SystemVerilog引入了C語言中的跳轉語句break和continue,使循環控制更加靈活,代碼更加直觀和簡潔。語句continue指跳出或結束本次循環,進入到下一次循環的判斷中;而break語句是跳出或結束整個循環。8.2.7任務和函數SystemVerilog為VerilogHDL的任務和函數增強了一些功能,使復雜電路的設計和驗證更加靈活高效,具體見表8.2-3。8.2.8包VerilogHDL中參數、任務和函數必須在模塊內部定義,如果多個模塊中使用同樣的參數、任務或函數,則不得不重復定義或使用`ifdef或`include編譯預處理指令,增加了代碼編寫量,同時代碼維護性也差。SystemVerilog通過增加用戶自定義的包(package)解決這一問題,package提供了一個聲明,它可以在任何模塊中引用。package可包含的內容包括:·參數定義語句parameter/localparam;·常數定義語句const;·自定義數據類型typedef;·任務和函數定義task/function;·包的輸入語句import;·包的輸出語句export。在alu_types包中,包含了局部參數DELAY定義、自定義數據類型bus32_t和bus64_t定義、枚舉類型opcode_t和結構體instr_t定義,以及函數parity_gen定義。包定義后可被多個模塊使用,其調用語法是:包名
::8.2.9接口VerilogHDL模塊之間的連接是通過模塊端口進行的,SystemVerilog提供了一個較高層次抽象的模塊端口封裝機制,稱為接口(interface)。接口是將一組信號封裝在一起作為一個獨立的端口,它獨立于模塊。其語法如下:若在模塊內部使用接口,使用前需將這個接口實例化,語法為接口名
實例名(端口連接);8.3基于SystemVerilog的仿真驗證專用集成芯片設計的復雜度以指數形式增長,這使得驗證工作成為芯片設計流程中的瓶頸,有關數據表明,接近70%~80%的設計時間花費在了功能驗證中。預測所有可能的極端情況并發現隱藏的設計錯誤是功能驗證的關鍵,同時在驗證過程中希望能盡早發現這些錯誤已滿足項目資源和上市時間的要求。SystemVerilog提供了用于描述復雜驗證環境的語言結構,如增加約束隨機產生激勵,覆蓋率統計分析提高自動化驗證效率,斷言驗證檢測設計者意圖并診斷錯誤,特別是引入了面向對象的編程結構,有助于采用事務級的驗證和提高驗證的重用性。這些特性允許用戶開發生成各種驗證場景的測試平臺,一種典型的可重用測試平臺如圖8.3-1所示。在圖8.3-1中,信號發生器Generator產生不同輸入激勵送到驅動模塊Driver中,接口Interface包含了所有的設計端口信號,用于驅動和監控;驅動Driver將產生的激勵信號通過Interface送給被測電路;監視器Monitor通過監控被測電路DUT的輸入/輸出信號,從而捕獲電路行為;計分板ScoreBoard包含參考模型ReferenceModel和比較邏輯ComparisionLogic,參考模型接收激勵信號并產生期望值,比較邏輯將DUT輸出與期望值進行比較。在成功比較后,計分板產生功能覆蓋。Environment包含上面提到的所有驗證組件,構成一個通用的測試環境。測試Test實例化Environment對象,生成一個特定的測試場景。下面介紹在上述測試平臺中需要用到的與測試相關的SystemVerilog語法。8.3.1面向對象的編程過程編程語言如VerilogHDL、C的數據定義和對數據的操作是各自獨立的。例如,在VerilogHDL中,數據聲明和函數或任務可以獨立定義,沒有任何形式的聯系;一個函數可以對多個數據進行操作,多個函數可以對同一個數據進行操作。這種情況下,程序的功能會變得難以理解。在面向對象編程語言中,數據和對數據的操作可以封裝到一個獨立的對象中。面向對象編程(Object-OrientedProgramming,OOP)是一種成熟的計算機編程模型,它是圍繞數據或者對象而不是功能邏輯來組織的,它能夠提高代碼可重用性和開發效率。SystemVerilog引入了C++?語言中“類”的概念。類描述的是一組有相同特性(屬性)和相同行為(方法)的對象。在程序中,類實際上就是數據類型,就像整型、實數型一樣。在驗證平臺中,類和對象對于激勵的產生和數據的高層抽象很有幫助,如類可以用來封裝一個通用的操作,從而在驗證平臺的不同地方重用。1.類的定義下面定義了一個名為“Packet”的類,類的內部定義了數據變量(也稱為屬性)command/address/master_id/i,以及對這些數據變量(屬性)進行處理的任務clean和函數new/get。其中new()函數被稱為構造函數。構造函數用于實例化類時為其初始化,如下面代碼中對變量command、address和master_id賦初值。類中的構造函數只能有一個,且沒有返回值。2.類的聲明(句柄的聲明)類就像用戶自定義的一種數據類型,在module/class/function/task等地方可以創建變量為某個類的類型。3.類的實例化(創建對象)通過構造函數new()對句柄初始化,創建了類的對象,如下面的“my_packet=new();”,此時對象名即變量名,也是對象的實際句柄。通過new()這個構造函數給對象分配內存空間,并且把實際入口地址賦給對象的句柄my_packet。上述task端口變量myexample是obj_example類型,功能是判斷句柄myexample是否初始化,如果沒有初始化,則通過new創建新的對象,并且句柄myexample指向這個新的對象。如果在類的定義中,函數的參數和類屬性的命名相同,如下面Demo_this類中變量x既是類的屬性,也是函數new()的參數,此時需要加“this”進行區別。關鍵字this用于明確引用當前對象的類屬性或方法。在new()函數中將形參x的數值賦給Demo_this對象中的變量x。4.使用對象就如Verilog中的層次化引用一樣,通過“.”操作符來訪問對象中的成員。例如:Packetmy_packet;//定義變量my_packet類型是Packet類5.類的繼承和多態繼承是類中一個非常重要的概念,是讓一個類(子類)獲得另一個類(父類)的屬性和方法的途徑。通過使用關鍵詞“extends”,子類不僅可以繼承并修改父類的所有屬性和方法,還可以創建自己的屬性和方法。在實際應用中,將共性的屬性和方法放在父類中,子類只關注自己特有的屬性和方法,這樣提高了代碼的擴展性。在下面的代碼中,類LinkedPacket是Packet的子類,它繼承了Packet中所有的屬性和方法,就像它們在自己類內定義的一樣;同時LinkedPacket還有自己的函數get_next()和屬性j。子類對象是其父類的合法對象。每個LinkedPacket對象是一個完全合法的Packet對象,例如:LinkedPacketlp=new;Packetp=lp;LinkedPacket對象的句柄可以賦給Packet變量。在這種情況下,對p的引用可以訪問Packet類的方法和屬性。在下面的代碼中,子類LinkedPacket定義了一個和父類Packet同名的函數get()和成員i,通過p引用的這些被重寫的成員得到的是父類Packet類中的原始屬性和方法,因此變量j的值都為1。如果子類引用父類中的成員,特別是當父類的成員被子類成員覆蓋時,必須用關鍵字super來訪問父類成員。將上面LinkedPacket類改寫成:對象lp是子類LinkedPacket,用super.i獲取了父類Packet中定義的成員i,所以結果為-1。上面提到將一個子類句柄賦給一個父類句柄(向上轉型),這通常是合法的;但是將一個父類句柄賦值給一個子類句柄(向下轉型),需要利用關鍵字$cast強制轉換,如下所示,將Packet句柄pp強制轉換成LinkedPacket子類句柄lpp。6.抽象類和虛方法在類名前加上關鍵字virtual的類稱為抽象類,抽象類不能實例化,只能被繼承。若將Packet類定義的第一行改寫成“virtualclassPacket;”,這時用“Packetp=new;”就會報錯。在解釋繼承時可知,將子類句柄賦給父類句柄后,若調用子類和父類中的同名方法,賦值后的父類句柄調用的方法還是父類的方法,這是因為普通方法的調用取決于調用該方法的句柄類型,而不是句柄指向對象的類型。如果想在子類中覆蓋父類的方法,則可以在父類的方法前加上關鍵字virtual,也就是將父類方法變為虛方法;對于虛方法的調用取決于句柄指向的對象類型,而非句柄類型。如下面代碼,將Packet中的函數get改成虛函數,此時p.get()返回值是通過子類對象和方法計算得到的數值,即-2。在類中如果有接口定義,在接口名前面也可以加關鍵字virtual,即virtualinterface_name。當它作為一種數據類型使用時,保存著對實際接口的句柄,這意味著class可以使用virtualinterface來驅動該interface,而不是直接應用DUT接口信號。virtualinterface提供了一種將驗證平臺抽象模型與設計的實際接口信號分開的機制,促進了代碼的重用,對底層設計的接口更改不需要重寫使用virtualinterface的代碼。7.數據隱藏和封裝將類中的數據隱藏,并且通過方法來訪問的技術叫做封裝。在默認情況下,類中的所有成員都可以通過對象的句柄來訪問,但是多個對象句柄訪問可能會破壞某些類成員的值。為了限制外部對象對類內部成員的訪問,可以在成員名前加上前綴local或protected。通過聲明成員為local成員來避免對此類成員的外部訪問(父類的對象也不能訪問,這種訪問也屬于外部訪問),任何違規都可能導致編譯錯誤,local成員對于子類來說也不可見,所以不能通過子類來訪問local成員。8.3.2隨機約束在VerilogHDL中使用$random系統函數產生隨機激勵來檢測隱藏的設計漏洞。但是純粹的隨機激勵需要很長時間才能產生有意義的效果,而且不一定符合芯片設計規范,如隨機產生的激勵可能不滿足總線接口時序規范。因此,在SystemVerilog中提出給隨機施加一定約束條件的思想,通過對隨機測試用例施加一定的約束,將隨機用例約束在仿真驗證期望的區間內,從而提高隨機激勵的效率。對于不需要關心的測試空間,通過約束條件進行關閉,可提高測試向量的有效性;利用隨機種子反復地運行隨機激勵,不同的隨機種子隨機出來的測試向量不同,從而覆蓋不同的測試空間。隨機約束不但可以減少編寫測試向量的數目和驗證代碼的行數,還可能覆蓋到事先沒有預料到的邊界測試空間(CornerCase),從而發現隱藏的錯誤。但是隨機測試的驗證環境比定向測試的復雜,需要隨機激勵、參考模型和比較邏輯(如圖8.3-1所示)。SystemVerilog提供一種緊湊的、聲明式的方式指定約束。下面介紹約束隨機測試所需的常用語法。1.隨機數產生系統函數和傳統VerilogHDL一樣,SystemVerilog也內置了一些系統函數來產生隨機激勵,如$urandom、$urandom_range,以及一些標準概率分布的系統函數,如$random、$dist_uniform、$dist_normal等。2.隨機分支randcase和隨機序列randsequence關鍵字randcase引入了一個case語句,該語句隨機選擇它的一個分支。randcase項表達式是組成分支權值的非負整數值。一個分支的權重除以所有權重的和,就得到了選擇該分支的概率。3.面向對象的隨機上節提到面向對象的編程極大提高了驗證的可擴展性,SystemVerilog也可為對象的成員變量提供隨機激勵。基于對象的隨機生成包含了三個部分:定義隨機變量類型、指定約束條件(可選)、通過調用內置randomize()方法產生隨機。隨機變量的類型有兩種:rand和randc。rand關鍵字聲明的變量是標準隨機變量,它們的值均勻地分布,如“randbit[7:0]y;”是一個8位無符號整數,取值范圍是0~255。如果不受約束,則該變量應被賦值為0~255的任意值,概率相等,即連續隨機化時重復相同值的概率是1/256。用randc關鍵字聲明的變量是隨機循環變量,只能是位類型或枚舉類型,并且可以限制最大值。其基本思想是randc隨機遍歷規定范圍內的所有值,并且在一次遍歷中沒有重復值。當遍歷結束時,一個新的隨機遍歷自動開始。如“randcbit[1:0]y;”,變量y可以取值0、1、2和3(范圍為0~3)。randomize計算y范圍內的初始隨機排列,然后在后續調用中按順序返回這些值。當返回一個排列的最后一個數值后,再計算一個新的隨機排列來重復這個過程。
在面向對象的隨機變量中,通常加上約束條件限制隨機變量的數值范圍。約束條件也稱為約束塊,它是類中的獨立成員,類似于類任務、函數和變量,約束塊名在類中必須是唯一的。其基本語法為約束條件及隨機過程控制通常有下面幾種機制:(1)集合成員約束:用inside操作符產生一個隨機數的集合,隨機變量在這個集合中選取,且每個值取到的概率相同。(2)概率分布約束:dist操作符帶有一個值的列表以及相應的權重,中間用“:=”或“:/”分開。“:=”操作符表示范圍內的每個值的權重是相同的,“:/”表示權重要均分到每一個值。(3)條件約束:使用指示運算符或if-else結構。(4)函數約束:有時約束條件很難用簡單的隨機種子或范圍來描述,因此SystemVerilog提供了用函數來描述約束。(5)迭代約束:使用關鍵字“foreach”,允許循環變量和索引表達式以參數化的方式約束數組變量。8.3.3覆蓋率上一節中基于約束的隨機激勵測試可以檢測隱藏的設計漏洞或設計邊角情況,提高驗證的狀態或功能點數,但這些功能點可能是局部的。通常驗證必須是全面的,因此覆蓋率被提出來并作為衡量驗證是否通過或滿足要求的標準。覆蓋率有代碼覆蓋率和功能覆蓋率兩種。本節主要討論功能覆蓋率統計方法。功能覆蓋率是一個用戶自定義的度量,用以度量有多少設計規范已經被執行,如測試計劃中的測試用例。它用于度量有效場景、角落用例、規范不變性或其他應用設計條件是否已經被觀察、驗證和測試。功能覆蓋率有兩個重要的特征:它是用戶自定義的,不是由設計自動推斷的;它建立在設計規范的基礎上,但又獨立于設計代碼和設計結構。因為功能覆蓋是完全由用戶指定的,所以它需要更多的前期工作(如編寫覆蓋模型);同時也需要結構化的驗證方法。SystemVerilog基于上述原因,提供兩種類型的功能覆蓋率:(1)面向控制的功能覆蓋率:通過cover對斷言中的sequence或者property作統計,這個將在8.3.4節中討論。(2)面向數據的功能覆蓋率:在特定的時間點對某些數據值使用coverpoint和covergroup作采樣統計分析。本節就簡要介紹這種功能覆蓋率。
1.覆蓋點覆蓋點(coverpoint)就是針對變量或者表達式的數值進行采樣的地方。SystemVerilog會為每個覆蓋點創建對應的一組倉(bin)來記錄每個數據被采集到的次數。如果采樣的變量是1bit位寬,最多有兩個bin被創建,即“0”倉和“1”倉。為了計算覆蓋率,首先需要確定每個覆蓋點上所有可能產生的數值個數,如采樣的變量是3bit位寬,就有8個不同的數值,創建8個倉。如果在仿真過程中有7個倉的值被采樣到,那么這個測試點的覆蓋率就是7/8。coverpoint的基本語法為coverpoint<變量/表達式1>iff(表達式2)其中,iff是可選項,表示當表達式2成立時,不作覆蓋率統計。上面語法產生的倉數及倉名是系統自動創建的,自動創建倉的最大個數由auto_bin_max確定,默認是64。如果一個變量是16位,有2^16?=?65?536個數值,數值超過了倉的個數時,會將值域范圍平均分到每個倉內,即每個倉都覆蓋了1024個數值。在如此龐大的倉內尋找沒有被覆蓋的點其工作量無疑是巨大的,因此SystemVerilog提供了用戶自定義倉來限制倉的個數或者創建有意義的倉,基本語法為bins/ignore_bins/illegal_bins倉名={數值集或數值轉換}iff(表達式2);其中,關鍵字bins表示創建一個倉,ignore_bins表示倉中的所有值都被排除在覆蓋范圍之外,illegal_bins表示所有與非法倉相關的值都被排除在覆蓋范圍之外;如果發生illegal,則發出運行錯誤警示。非法倉優先于任何其他倉,也就是說,即使它們也包含在另一個倉中,發生時也會導致運行錯誤。在自創建倉內,倉內除了有不同的數值外,還可以定義一個或多個數值轉換或數值序列,判斷這些數值序列是否被覆蓋、忽略或非法,如判斷value1=>value2=>value3=>value4這個數值序列。2.覆蓋組(covergroup)在同一采樣時間點上將多個覆蓋點組合在一起就構成了覆蓋組covergroup。類似class,covergroup也是一個用戶自定義類型,在module/program/interface/class/package等結構內定義,通過new構造實現多次實例化,其基本語法為覆蓋組可以定義形式參數列表,在new實例化時將實參傳遞給形參;可以明確定義功能覆蓋組的采樣條件,若不定義時鐘采樣條件,則通過默認的sample函數采樣;通過coverpoint和cross語句定義采樣對象。3.交叉覆蓋點覆蓋組內可以通過關鍵字cross對兩個或者多個覆蓋點指定交叉覆蓋點。若cross指定的交叉覆蓋點中的成員是一個變量,但沒有用coverpoint定義,則系統會自動為該變量創建對應的覆蓋點;但成員不能是沒有用coverpoint定義的表達式,這種情況必須先為表達式定義覆蓋點。8.3.4SystemVerilog斷言1.什么是斷言?傳統的驗證基本原理是根據電路需求編寫激勵信號或測試向量,將測試向量連接到被驗證模塊的輸入端,在其輸出端收集數據,并進行時序或者數據分析,達到查找設計缺陷的目的。這種方法根本上是屬于覆蓋率驅動的動態仿真。隨著系統級芯片設計復雜度的不斷提高,上述傳統驗證方法的弊端越來越明顯,比如為了滿足覆蓋率的要求,需要編寫運行大量的測試向量來查找設計中的缺陷,消耗大量的人力資源和仿真資源;驗證工程師需要通過分析波形和日志文件來檢查及定位設計中的錯誤,這種分析方法在系統級驗證中效率低下,不利于產品上市周期。設計能力與驗證能力之間差距的不斷增大,迫使人們去探究新的驗證方法以彌補現有驗證方法的不足,因此基于斷言的驗證技術(Assertion_BasedVerification,ABV)被提出并應用在系統級電路驗證中。斷言(assertion)是對設計屬性(property)(行為)的描述,它并不是一個全新的概念,最初在軟件設計中得以應用。斷言的概念最早出現于1949年AlanTuring在高速自動計算機器(HighSpeedAutomaticCalculatingMachines)會議論文中所提及的一段敘述:“Inorderthatthemanwhochecksmaynothavetoodifficultatask,theprogrammershouldmakeanumberofdefiniteassertionswhichcanbecheckedindividually,andfromwhichthecorrectnessofthewholeprogrameasilyflows.”(為了降低驗證難度,程序員應該設計一些明確的斷言,這些斷言可以單獨檢查,并且很容易從中判斷整個程序是否正確。)斷言總是和靜態仿真工具結合在一起使用,對電路進行形式驗證。形式驗證是通過數學的方法遍歷所有工作狀態,它克服了傳統動態仿真難以窮舉所有可能的測試序列去完全覆蓋狀態的缺點。基于斷言的驗證方法如圖8.3-6所示。首先根據設計規范制定測試場景,從測試場景中抽象出屬性(行為)并用斷言表示,這些斷言可以插入到設計文件中,也可以單獨編成一個斷言文件;將設計文件和對應的斷言文件送入形式驗證工具中仿真驗證,在仿真過程中,斷言就類似一個監控器,監視那些屬性;如果一個被描述的屬性不是期望的那樣,這個斷言就會失敗,并給出反例用于驗證者核查錯誤,進而修改設計或進一步約束屬性,使其更精確地描述設計行為。斷言包括用戶自定義的斷言和專門的斷言庫(如OVL(OpenVerificationLibrary)),能夠進行屬性描述、接口約束、激勵序列產生、功能覆蓋率檢查及形式驗證分析等。使用斷言的驗證技術的優點有如下幾點。(1)提高了驗證效率:用簡潔的語言結構描述了復雜準確的時序關系;一旦發生設計錯誤,斷言能立即檢測及定位,提高驗證的可觀察性;致命錯誤發生后,斷言可以終止仿真,提高驗證的可控性。(2)提升了功能覆蓋率:斷言作為設計屬性(行為)的描述,通過對斷言執行情況的覆蓋統計,可以將傳統的代碼覆蓋率提升到功能覆蓋率,與仿真環境中原有的功能覆蓋點相結合,構建完整的功能覆蓋機制。(3)可重用性強:基于“黑盒子”的斷言技術與具體電路實現無關,一般寫在單獨的斷言文件中,用來描述電路輸入/輸出應滿足的設計要求;尤其是針對標準協議編寫的斷言,它們可以面向不同的設計。(4)支持跨時鐘域的時序驗證:現在大多數的設計是基于多時鐘域的,當跨越不同的時鐘域時,使用多個時鐘斷言屬性對于數據完整性檢查非常有幫助。用之前學習的VerilogHDL可以實現斷言的功能,如下面的Verilog代碼設計了一個斷言。當定義宏名DEBUG時,這個檢驗器生效并產生一個斷言,即信號a和b不能同時為高電平,如果發生了上述情況,則打印錯誤信息。雖然VerilogHDL代碼結合系統任務或函數可以實現一些檢驗任務,但是VerilogHDL本質上是一種過程性語言,其設計目的是用于硬件電路設計,而不是電路的仿真驗證,因此它不能很好地控制產生復雜時序。要描述復雜的時序關系,VerilogHDL需要編寫冗長的代碼,如例8.3-8所示的時序(見圖8.3-7):在時鐘上升沿判斷信號a是否為高;延時1個時鐘周期,判斷信號b是否為高;再延時2個時鐘周期,判斷信號c是否為高。這樣復雜的時序代碼編寫容易出錯且不易維護;由于VerilogHDL的過程性,使得它很難檢測同一時間段發生的所有并行事件;更糟糕的是,用VeilogHDL編寫的斷言可能與它們要驗證功能的實現方式相同并包含相同的錯誤,從而無法檢測到共同錯誤。鑒于VerilogHDL編寫斷言可能存在的以上問題,SystemVerilog開發了編寫斷言的專用語言SystemVerilogAssertion。2.SystemVerilog斷言的建立過程SystemVerilogAssertion(SVA)是一種描述性的語言,它提供了一種強大的替代方法為設計編寫約束、檢查器和覆蓋點;同時語言本身也簡單,易于管理。如例8.3-8中需要驗證的時序關系,用SVA描述,只需一行代碼:
abc_ast:assertproperty(@(posedgeclk)a|->##1b##2c);同時從例8.3-8中看出,時序驗證的失敗和成功的結論必須在VerilogHDL中額外用$display定義,而SVA中斷言失敗會自動顯示錯誤信息。
SVA的建立過程如圖8.3-8所示,包括布爾表達式、序列(Sequence)、屬性(Property)、斷言(AssertProperty)和覆蓋語句(CoverProperty)。1)布爾表達式布爾表達式位于最底層,和VerilogHDL中沒有差別,如“a&&b;”。2)序列在任何設計中,序列都是由多個邏輯事件組合而成的。這些事件可以是同一時鐘沿被求值的簡單布爾表達式,也可以是經過多個時鐘周期后求值計算得到的事件。SVA使用關鍵字sequence(序列)來表示這些事件,其基本語法為3)屬性許多序列可以被有序地組合起來形成設計的屬性,用關鍵字property來表示屬性。屬性也可以由表達式構成。屬性是在模擬過程中被驗證的單元,只有在斷言中被調用,才能真正發揮作用。其基本語法為4)斷言斷言是對特定屬性或者序列進行行為檢查,其基本語法為assertion_name:assertproperty(property_name);其執行方式與過程if語句相同,即如果表達式的計算結果為X、Z或0,那么表達式被解釋為假,斷言失敗;否則,表達式被解釋為真,斷言成功。5)覆蓋為了保證驗證的完備性,需要統計功能覆蓋率信息,在SVA中提供關鍵字cover來實現這一功能,其基本語法為cover_name:coverproperty(property_name);其中,property_name是需要覆蓋的屬性名。覆蓋語句執行結束后,可得到的信息包括屬性驗證的次數、屬性成功的次數、屬性失敗的次數及屬性“空成功”(VacuousSuccess)的次數。3.斷言的種類SystemVerilog語言中定義了兩種斷言:即時斷言(ImmediateAssertion)和并發斷言(ConcurrentAssertion)。1)即時斷言即時斷言基于事件的變化,表達式的計算就像VerilogHDL中的組合邏輯賦值一樣,是立即被求值判斷的,而不是時序相關的。它放在過程塊的定義中,主要用于動態仿真。2)并發斷言一般的,斷言是基于時序邏輯的,單純進行組合邏輯的斷言很少,因此在這里重點介紹面向時序檢查的并發斷言所涉及的常用語法。并發斷言的一般規則是“time+sequence”,首先要指定斷言被觸發執行的時刻,一般情況是用時鐘上升(下降沿)來觸發,即@(posedgeclk)或@(negedgeclk)。并發斷言可以放在always或initial過程塊中,也可以像連續賦值語句一樣單獨成行。并發斷言可以在靜態(形式化)驗證工具和動態(仿真)驗證工具中使用。
4.斷言定義中常用的語法結構下面介紹在斷言定義中常用的一些語法結構。1)斷言失效在驗證中,當某些條件滿足時,不用進行斷言的檢測,如當復位信號有效時,讓斷言不工作;SVA提供了關鍵詞“disableiff”來實現驗證在某些情況下的失效,其基本語法為disableiff(expression)property_expr;如在異步復位觸發器中判斷輸出信號q是否等于輸入信號d,若直接編寫斷言@(posedgeclk)(q==$past(d)),則當復位信號有效時就會報錯,因此需要改寫成當復位信號無效時進行斷言的判斷,將上句重新改寫為@(posedgeclk)disableiff(!rst_n)(q==$past(d))//rst_n是低電平有效時鐘clk上升沿到來,首先判斷復位信號rst_n是否為低電平,如果rst_n是低電平,則不進行q==$past(d)的判斷;rst_n為高電平,才進行輸出信號q是否等于上一個時鐘輸入信號d數值的判斷。2)蘊含結構上述時序驗證只是在每個時鐘有效沿檢查對應的布爾表達式是否成立,但在復雜時序的檢驗中,往往需要驗證若干個時鐘周期內發生的多個事件,而且這些事件存在時序先后關系。比如在時鐘信號clk上升沿時,首先判斷事件A是否成立,如果不成立,則斷言失敗;如果成立,再判斷事件B是否成立,這就相當于一個if-else結構:其中,事件A稱為“先行算子”(antecedent),事件B稱為“后續算子”(consequent)。當先行算子成功時,后續算子才會被計算判斷。如果先行算子不成功,那么整個屬性默認為“空成功”。這種由先行事件觸發后續事件的結構在SVA中稱為蘊含結構,它包括兩種類型:交疊蘊含(OverlappedImplication)和非交疊蘊含(Non-OverlappedImplication)。(1)交疊蘊含。交疊蘊含用符號“|->”表示,含義是如果先行算子成功,則在同一個時鐘周期計算并判斷后續算子是否成功。(2)非交疊蘊含。非交疊蘊含用符號“|=>”表示,含義是如果先行算子成功,則在下一個時鐘周期計算并判斷后續算子是否成功,即后續算子的判斷相對先行算子會有一個時鐘周期的延時。在一些復雜時序的設計中,先行算子和后續算子的發生往往不在同一時鐘周期或僅一個時鐘周期延時,可能后續算子的發生相對于先行算子有若干個時鐘周期的延時,因此SVA提供了帶有延時的蘊含,時鐘延時用“##”表示,具體形式如下:3)重復運算符在時序設計中往往需要某個信號或序列重復發生,如下面的序列:@(posedgeclk)$rose(start)|->##1a##1a##1a##1stop;表示在時鐘上升沿,若信號start發生了上跳變,則從下一個時鐘起,信號a保持在3個連續時鐘周期內為高電平,然后在下一個時鐘周期,信號stop為高。如果信號a要在多個時鐘周期保持高電平,上述寫法會使代碼冗長,因此SVA中提供了3種不同機制的重復運算符。(1)連續重復:判斷信號或序列是否在指定的n個時鐘周期內連續發生,其基本語法為signalorsequence[*n](2)跟隨重復:判斷信號或序列是否發生了n次,但這些序列不一定是在連續時鐘周期內發生的,但要求重復序列的最后一次發生應該在整個序列結束之前。其基本語法為signalorsequence[->n](3)非連續重復:與跟隨重復相似,但它并不要求重復序列的最后一次發生應該在整個序列結束之前。其基本語法為signal[=n]如序列“start##1a[=3]##1stop”表示在信號stop為高電平之前,信號a要連續或間接地出現3個高電平,但在信號stop為高電平的前一個時鐘周期,信號a不一定為高電平。上面定義的重復次數是固定值,利用[*min:max]語法可以定義重復次數的范圍,其中min代表最小重復次數,min可以為0,代表一次也不發生;如果沒有重復次數的限制,可以將右邊最大重復次數max用“$”表示。4)局部變量的使用局部變量是SVA語言中重要的特性之一,它使得檢查設計中復雜的流水線行為成為可能。SVA中的局部變量是動態變量,也就是說,它在序列啟動時動態創建,在序列結束時自動刪除。局部變量在序列或屬性內部定義并賦值。局部變量的定義是單獨語句,但變量的賦值語句必須和子序列結合,并放在子序列的后面,用逗號隔開。如果子序列匹配成功,則變量才能被賦予新值。5)多時鐘域檢測SVA允許序列或者屬性使用多個時鐘域來采樣信號及檢測子序列。多時鐘域序列是通過使用單時鐘域子序列連接延時操作符##1或##0來構建的。6)斷言系統函數SVA提供總線斷言函數和時序檢查的系統函數來快速有效建立斷言,表8.3-1列舉了一些常用斷言函數。5.SVA與功能覆蓋斷言中也提供了測量覆蓋率的工具,關鍵字為“cover”。其基本語法為cover_name:coverproperty(property_spec);其中,cover_name表示覆蓋名稱,property_spec表示要覆蓋的屬性。6.SVA輸入約束在形式驗證中,形式工具會盡可能地遍歷所有的合法輸入空間。為了降低形式驗證復雜度,提高驗證有效性,在斷言中提供可對設計輸入約束的語法assume。其基本語法為assume_name:assume(property_spec)其中,assume_name表示約束名稱,property_spec表示要約束的屬性。7.?SVA與設計的連接將SVA連接到對應的設計中有如下兩種方法:(1)在模塊(module)定義中斷言檢驗器,稱之為內部斷言;(2)將斷言檢驗器與模塊、模塊的一個或多個實例綁定,稱之為外部斷言。1)內部斷言斷言放在設計模塊的內部,方便在仿真時查看異常情況。當異常出現時,斷言會自動報警,其具體結構如下:模塊內部斷言一般用在內部信號或時序的判斷上,一般將它和關系密切的RTL代碼放在一起,以保持一致性。需要注意的是,編寫的RTL代碼不能破壞斷言的正確執行,若斷言自身存在和它想要驗證的行為相同的錯誤,則斷言將無法檢測這些錯誤。內部斷言最好放在`ifdef塊中,當工具不支持或設計(仿真)者不使用內部斷言時,可通過取消相應預處理宏名的定義來自動去掉斷言。內部斷言一般由設計工程師編寫插入,基于電路的具體實現來設計,類似“白盒”技術;有效的內部斷言可以提高設計的可觀察性,能及時發現設計的錯誤,并能降低仿真調試時間。2)外部斷言為了保證設計代碼的完整性,SystemVerilog在斷言中提供了bind功能,將斷言單獨做成子模塊,并通過bind把斷言子模塊與設計模塊連接起來,使得兩者互不影響。這樣做的好處是:(1)即使設計代碼有微小的改動,驗證工程師也能夠基于原來的環境進行驗證。(2)提供了一個簡便機制來使驗證斷言IP能迅速添加到一個子模塊中。(3)不會使斷言產生任何語義上的改變,這相當于使用分級路徑名將斷言寫入模塊外部,保證了程序的穩定性和可靠性。bind的基本語法為bind模塊名
斷言子模塊名
斷言實例名(端口列表);8.4SystemVerilog與C語言接口VerilogHDL編程語言接口(ProgramLanguageInterface,PLI)為VerilogHDL和其他編程語言提供了一個交互機制。SystemVerilog對PLI進行擴展,形成了一種新的Verilog代碼和其他編程語言(通常是C/C++)相互通信的接口方式,稱為直接編程接口DPI(DirectProgrammingInterface)。DPI相對于傳統的PLI,最大的優
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 施工現場施工安全管理的基本任務試題及答案
- 新能源汽車技術與政策之間的互動關系試題及答案
- 音樂三年級試卷及答案
- 理解行業發展動態的英語交流試題及答案
- 機修崗位考試題及答案
- 大學物理教程試題及答案
- 深入分析商務溝通中的障礙試題及答案
- 數字與形狀考察中的基礎課題題試題及答案
- 新穎幼兒園數學考試試題及答案
- 新能源汽車用戶體驗優化策略試題及答案
- 山東省德州市陵城區2024-2025學年下學期期中考試七年級數學試題(含答案)
- 鄉村振興面試題及答案
- 2025廣東高考:歷史必考知識點總結
- 剪輯考試試題及答案
- 火鍋店服務員接待流程解析
- 2025年上半年福建福州廣播電視臺招聘重點基礎提升(共500題)附帶答案詳解
- 高中政治經濟主觀題材料對應術語總結
- 2025年金融數學考試試題及答案
- 2024年安徽省公務員【申論】考試真題及答案-(A卷+B卷+C卷)三套
- 浙江國企招聘2024溫州市公用事業發展集團有限公司招聘8人筆試參考題庫附帶答案詳解
- 研發月報工作總結
評論
0/150
提交評論