哪一些網(wǎng)站可以開(kāi)戶做百度廣告長(zhǎng)沙seo推廣公司
OCP Open Closed Principle 開(kāi)閉原則
文章目錄
- 隨機(jī)約束和分布
- 為什么需要隨機(jī)?
- 為什么需要約束?
- 我們需要隨機(jī)什么?
- 聲明隨機(jī)變量的類
- 什么是約束
- 權(quán)重分布
- 集合成員和inside
- 條件約束
- 雙向約束
- 約束塊控制
- 打開(kāi)或關(guān)閉約束
- 內(nèi)嵌約束
- 隨機(jī)函數(shù)
- pre_randomize 和 post_randomize
- 系統(tǒng)隨機(jī)數(shù)函數(shù)
- 隨機(jī)化個(gè)別變量
- 數(shù)組約束
- 約束數(shù)組的大小
- 約束數(shù)組的元素
- 產(chǎn)生唯一元素值的數(shù)組
- 隨機(jī)化句柄數(shù)組
- 隨機(jī)控制
- 參考資料
隨機(jī)約束和分布
為什么需要隨機(jī)?
- 芯片復(fù)雜度越來(lái)越高,在20年前 定向測(cè)試 已經(jīng)無(wú)法滿足驗(yàn)證的需求,而 隨機(jī)測(cè)試 的比例逐漸提高。
- 定向測(cè)試能找到你認(rèn)為可能存在的缺陷,而 隨機(jī)測(cè)試可以找到連你都沒(méi)有想到的缺陷 。
- 隨機(jī)測(cè)試的環(huán)境要求比定向測(cè)試復(fù)雜,它需要激勵(lì)、參考模型和在線比較。上百次的仿真不再需要人為參與,以此來(lái)提高驗(yàn)證效率。
- 隨機(jī)測(cè)試相對(duì)于定向測(cè)試可以減少相當(dāng)多的代碼量,而產(chǎn)生的激勵(lì)較定向測(cè)試也更多樣。
為什么需要約束?
- 如果隨機(jī)沒(méi)有約束,產(chǎn)生有效激勵(lì)的同時(shí),還 會(huì)產(chǎn)生大量的無(wú)效激勵(lì) 。
- 通過(guò)為隨機(jī)添加約束,這種 隨機(jī)自由是一種合法的隨機(jī) ,產(chǎn)生有效的測(cè)試激勵(lì)。
- 約束不是一成不變的,為了獲取期望的測(cè)試范圍或期待的數(shù)值范圍,約束需要“變形”。
- 隨機(jī)的對(duì)象不只是一個(gè)數(shù)據(jù),而是 有聯(lián)系的變量集合 。通常這些變量集合會(huì)被封裝在一個(gè)數(shù)據(jù)類里,同時(shí)需要類中聲明數(shù)據(jù)之間的約束關(guān)系。因此,約束之后要產(chǎn)生一個(gè)隨機(jī)數(shù)據(jù)的“求解器”,即在滿足數(shù)據(jù)本身和數(shù)據(jù)之間約束關(guān)系的隨機(jī)數(shù)值解。
- 約束不但 可以指定數(shù)據(jù)的取值范圍 ,還 可以指定各個(gè)數(shù)值的隨機(jī)權(quán)重分布 。
我們需要隨機(jī)什么?
- 器件配置: 通過(guò)寄存器和系統(tǒng)信號(hào)。
- 環(huán)境配置: 隨機(jī)化環(huán)境,例如合理的時(shí)鐘和外部反饋信號(hào)。
- 原始輸入數(shù)據(jù): 例如MCDF數(shù)據(jù)包的長(zhǎng)度、帶寬,數(shù)據(jù)間的順序。
- 延時(shí): 握手信號(hào)之間的時(shí)序關(guān)系,例如valid和ready,req和ack之間的時(shí)序關(guān)系。
- 協(xié)議異常: 如果反饋信號(hào)給出異常,那么設(shè)計(jì)是否可以保持后續(xù)數(shù)據(jù)處理的穩(wěn)定性。
聲明隨機(jī)變量的類
- 隨機(jī)化是為了產(chǎn)生更多可能的驅(qū)動(dòng),我們傾向于將相關(guān)數(shù)據(jù)有機(jī)整理在一個(gè)類的同時(shí),也用“rand”關(guān)鍵詞來(lái)表明它的隨機(jī)屬性。
- “randc”關(guān)鍵詞表示周期性隨機(jī),即所有可能的值都賦過(guò)值后隨機(jī)才可能重復(fù),也就好比54張撲克牌抽牌游戲,rand代表每抽完一張放回去才可以下次抽牌,randc代表沒(méi)抽完一張不需要放回就抽取下一張,如果抽完了,那就全部放回再次同樣規(guī)則抽取。
- rand和randc,只能聲明類的變量,硬件域以及軟件域的局部變量都不可以。
- 隨機(jī)屬性需要配合SV預(yù)定義的隨機(jī)函數(shù)std::randomize()使用。即通過(guò)聲明rand變量,并且在后期調(diào)用randomize()函數(shù)才可以隨機(jī)化變量。
- 約束constraint也同隨機(jī)變量一起在class中聲明。
class packet;rand bit [31:0] src, dst, data[8];randc bit [7:0] kind;constraint c {src >10;src <15;}
endclass//----------------------------------Packet p;
initial beginp = new();//assert語(yǔ)句保證randomize成功,否則會(huì)報(bào)fatal(如果約束沖突,如src>15 and src<10則會(huì)隨機(jī)失敗)assert (p.randomize()) else $fatal(0, "Packet::randomize failed");transmit(p);
end
白話一刻
* `class packet;`:定義一個(gè)名為`packet`的類。
* `rand bit [31:0] src, dst, data[8];`:聲明了三個(gè)隨機(jī)變量,分別是`src`(源地址)、`dst`(目標(biāo)地址)和`data`(一個(gè)包含8個(gè)元素的數(shù)組,用于存儲(chǔ)數(shù)據(jù))。每個(gè)變量的位寬度為32位。
* `randc bit [7:0] kind;`:聲明了一個(gè)隨機(jī)且唯一的變量`kind`,其位寬度為8位。`randc`意味著每次生成的`kind`值都是唯一的,直到所有可能的值都被使用完。
* `constraint c { ... }`:定義了一個(gè)約束`c`,用于限制隨機(jī)變量的取值范圍或關(guān)系。這里,它指定了`src`的值必須大于10且小于15。
* `Packet p;`:聲明了一個(gè)`packet`類型的變量`p`。注意,這里類名`packet`的首字母是大寫(xiě)的,這通常表示它是一個(gè)用戶定義的類型,而不是SystemVerilog的內(nèi)建類型。
* `initial begin ... end`:`initial`塊在仿真開(kāi)始時(shí)執(zhí)行一次。 + `p = new();`:創(chuàng)建一個(gè)新的`packet`對(duì)象,并將其賦值給變量`p`。 + `assert (p.randomize()) else $fatal(0, "Packet::randomize failed");`:調(diào)用`p`的`randomize`方法,該方法會(huì)根據(jù)類的約束隨機(jī)設(shè)置`p`的成員變量的值。`assert`語(yǔ)句檢查`randomize`是否成功。如果`randomize`失敗(例如,由于約束沖突),則執(zhí)行`else`部分的`$fatal`語(yǔ)句,導(dǎo)致仿真終止并輸出錯(cuò)誤消息。 + `transmit(p);`:調(diào)用一個(gè)名為`transmit`的函數(shù)(這個(gè)函數(shù)在提供的代碼片段中未定義),并將隨機(jī)化的數(shù)據(jù)包`p`作為參數(shù)傳遞。
總之,這段代碼定義了一個(gè)數(shù)據(jù)包類,并展示了如何創(chuàng)建和隨機(jī)化這個(gè)類的實(shí)例,以及如何將這個(gè)實(shí)例傳遞給一個(gè)函數(shù)。這對(duì)于在仿真中生成隨機(jī)化的數(shù)據(jù)包場(chǎng)景非常有用。
什么是約束
- 約束表達(dá)式的求解是有SV的約束求解器自動(dòng)完成的。
- 求解器能夠選擇滿足約束的值,這個(gè)值是由SV的PRNG(偽隨機(jī)數(shù)發(fā)生器)從一個(gè)初始值(seed)產(chǎn)生。只要改變種子的值,就可以改變CRT的行為。
- SV標(biāo)準(zhǔn)定義了表達(dá)式的含義以及產(chǎn)生的合法值,但沒(méi)有規(guī)定求解器計(jì)算約束的準(zhǔn)確順序。也就是,不同仿真器對(duì)于同一個(gè)約束類和種子求解出的數(shù)值可能不同。
- 什么可以被約束?SV只能隨機(jī)化二值數(shù)據(jù)類型,但數(shù)據(jù)位可以是二值或四值的,所以無(wú)法隨機(jī)出x值和z值,也無(wú)法隨機(jī)出字符串。
class date;rand bit [2:0] month; //note:rand bit [4:0] day;rand int year;constraint c_data {month inside {[1:12]};day inside {[1:31]};year inside {[2010:2030]};}}
endclass
請(qǐng)問(wèn):month=10,day=31,year=2020此組隨機(jī)值可以產(chǎn)生嗎?
答案:不能,因?yàn)閙onth的聲明是3位,所以不可能出現(xiàn)數(shù)值10,這也是經(jīng)常會(huì)犯的錯(cuò)誤,當(dāng)你約束數(shù)據(jù)時(shí),一定要與聲明數(shù)據(jù)的位數(shù)相匹配。
class stim;const bit [31:0] CONGEST_ADDR = 42; //聲明常數(shù)typedef enum {READ, WRITE, CONTROL} stim_e;randc stime_e kind;rand bit [31:0] len, src, dst;bit congestion_test;constraint c_stim {len < 1000;len > 0;if(congestion_test) (dst inside {[CONGEST_ADDR-100:CONGEST_ADDR+100]};src == CONGEST_ADDR;) else (src inside {0, [10:20], [100:200]};)}
endclass
權(quán)重分布
- 關(guān)鍵詞dist可以在約束中用來(lái)產(chǎn)生隨機(jī)數(shù)值的權(quán)重分布,這樣某些值的選取機(jī)會(huì)要大于其他值。
- dist操作符帶有一個(gè)值的列表以及相應(yīng)的權(quán)重,中間用 := 或 😕 分開(kāi)。值和權(quán)重可以是常數(shù),也可以是變量。
- 權(quán)重不要百分比表示,權(quán)重的和也不必是100。
- := 操作符表示值的范圍內(nèi)的每一個(gè)值的權(quán)重是相同的, 😕 操作符表示權(quán)重要平均分到范圍內(nèi)的每一個(gè)值。
rand int src, dst;constraint c_dist {src dist {0:=40, [1:3]:=60;}// src=1, weight=40/220// src=2, weight=60/220// src=3, weight=60/220// src=4, weight=60/220dst dist {0:/40, [1:3]:/60;}// dst=1, weight=40/100// dst=2, weight=20/100// dst=3, weight=20/100// dst=4, weight=20/100
}
這段代碼是使用SystemVerilog語(yǔ)言編寫(xiě)的,用于定義隨機(jī)數(shù)生成的約束。SystemVerilog通常用于硬件描述和驗(yàn)證。下面我將詳細(xì)解釋這段代碼:systemverilog
rand int src, dst;
這行代碼聲明了兩個(gè)隨機(jī)整數(shù)變量:src 和 dst。rand 關(guān)鍵字表示這些變量在仿真期間可以被隨機(jī)化。systemverilog
constraint c_dist { src dist {0:=40, [1:3]:=60;} dst dist {0:/40, [1:3]:/60;}
}
這部分定義了一個(gè)名為 c_dist 的約束,用于控制 src 和 dst 變量的隨機(jī)化分布。對(duì)于 src 變量:systemverilog
src dist {0:=40, [1:3]:=60;}
{0:=40} 表示當(dāng) src 變量取值為 0 時(shí),其權(quán)重是 40。
{[1:3]:=60} 表示當(dāng) src 變量取值為 1、2 或 3 時(shí),其權(quán)重是 60。
權(quán)重可以理解為生成特定值的概率或可能性。權(quán)重越高,生成該值的概率越大。對(duì)于 dst 變量:systemverilog
dst dist {0:/40, [1:3]:/60;}
{0:/40} 表示當(dāng) dst 變量取值為 0 時(shí),其權(quán)重是 40。
{[1:3]:/60} 表示當(dāng) dst 變量取值為 1、2 或 3 時(shí),其權(quán)重是 60。
注意,src 和 dst 的權(quán)重分布使用了不同的語(yǔ)法。src 使用了 := 運(yùn)算符,而 dst 使用了 :/ 運(yùn)算符。這實(shí)際上是一個(gè)語(yǔ)法錯(cuò)誤,因?yàn)樵赟ystemVerilog中,權(quán)重分布應(yīng)該使用統(tǒng)一的語(yǔ)法。通常,你會(huì)看到 := 用于指定絕對(duì)權(quán)重,而 :/ 用于指定相對(duì)權(quán)重。但在同一個(gè)約束中混合使用這兩種語(yǔ)法是不正確的。此外,注釋部分解釋了每個(gè)值的權(quán)重分布,但它似乎有些混淆,因?yàn)樗坪踉噲D將權(quán)重與可能的取值范圍相除來(lái)得到概率,但這不是正確的解釋。實(shí)際上,權(quán)重是獨(dú)立的數(shù)值,它們會(huì)被歸一化以表示生成特定值的相對(duì)概率。正確的解釋?xiě)?yīng)該是:對(duì)于 src,總權(quán)重是 40 + 60 * 3 = 220。因此,src 取值為 0 的概率是 40/220,取值為 1、2 或 3 的概率是 60/220。
對(duì)于 dst,由于代碼中的語(yǔ)法錯(cuò)誤,我們不能直接計(jì)算權(quán)重分布。如果假設(shè) dst 也使用絕對(duì)權(quán)重,并且語(yǔ)法被修正為 dst dist {0:=40, [1:3]:=60};,那么總權(quán)重將是 100(因?yàn)闄?quán)重被錯(cuò)誤地標(biāo)記為相對(duì)權(quán)重)。但實(shí)際上,dst 的權(quán)重分布應(yīng)該也使用絕對(duì)權(quán)重,并且總和應(yīng)該與 src 一致,以便進(jìn)行正確的概率計(jì)算。
為了修復(fù)這個(gè)問(wèn)題,你應(yīng)該選擇使用絕對(duì)權(quán)重或相對(duì)權(quán)重,并確保 src 和 dst 的權(quán)重分布語(yǔ)法一致。如果你使用絕對(duì)權(quán)重,代碼應(yīng)該類似于:systemverilog
rand int src, dst; constraint c_dist { src dist {0:=40, [1:3]:=20}; // 總權(quán)重為 80 dst dist {0:=40, [1:3]:=20}; // 總權(quán)重也為 80,以保持一致性
}
這樣,src 和 dst 就會(huì)有相同的權(quán)重分布,每個(gè)值都有相同的概率被選中。
集合成員和inside
- inside是常見(jiàn)的約束運(yùn)算符,表示變量屬于某個(gè)值的集合,除非還存在其他約束 ,否則隨機(jī)變量在集合里取值的概率是相等的(集合里也可以是變量)。
- 可以使用 $ 符指定最大或最小值。
rand int c;
int lo, hi;
constraint c_range{c inside {[lo:hi]};
}//-------------------------------rand bit [6:0] b;
rand bit [5:0] e;
constraint c_range {b inside {[$:4], [20:$]};e inside {[$:4], [20:$]};
}
條件約束
可以通過(guò) -> 或者 if-else來(lái)讓一個(gè)約束表達(dá)式在特定條件有效。
constraint c_io {(i_space_mode) -> addr[31] == 1'b1; //i_space_mode!=0
}//--------------------------------------constraint c_io {if(i_space_mode) //i_space_mode!=0addr[31] == 1'b1;else;
}
雙向約束
- 約束塊不是自上而下的程序代碼,它們是聲明性代碼,是并行的,所有的約束同時(shí)有效。
- 約束是雙向的,這表示它會(huì)同時(shí)計(jì)算所有的隨機(jī)變量的約束,增加或刪除任何一個(gè)變量的約束都會(huì)直接或間接的影響所有相關(guān)的值的選取。
- 約束塊可以聲明多個(gè),但是它們?nèi)耘f是并行的,如果對(duì)同一變量進(jìn)行約束,取兩者約束的交集,也就是兩個(gè)約束都會(huì)生效,與寫(xiě)在一個(gè)約束塊效果相同。
- 子類會(huì)繼承父類的約束。
約束塊控制
打開(kāi)或關(guān)閉約束
-
一個(gè)類可以包含多個(gè)約束塊,可以把不同約束塊用于不同測(cè)試。
-
一般情況下,各個(gè)約束塊之間的約束內(nèi)容是相互協(xié)調(diào)不違背的,因此通過(guò)隨機(jī)函數(shù)產(chǎn)生的隨機(jī)數(shù)可以找到合適的解。
-
對(duì)于其他情況,例如跟胡不同需求,來(lái)選擇使能哪些約束塊,禁止哪些約束塊,可以使用內(nèi)建函數(shù)constraint_mode()打開(kāi)或者關(guān)閉約束。
class packet;rand int length;constraint c_short {length inside {[1:32];}}constraint c_long {length inside {[1000:1032];}}
endclass//------------------------packet p;
initial beginp =new ();//create a long packet by disabling c_shortp.c_short.constraint_mode(0);assert(p.randomize());transmit(p);//create a short packet by disabling all constraint and then enable only c_shortp.constraint_mode(0);p.c_short.constraint_mode(1);assert(p.randomize());transmit(p);
end
內(nèi)嵌約束
- 伴隨著復(fù)雜的約束,它們之間會(huì)相互作用,最終產(chǎn)生難以預(yù)測(cè)的結(jié)果。用來(lái)使能和禁止這些約束的代碼也會(huì)增加測(cè)試的復(fù)雜性。
- 經(jīng)常增加或修改類的約束也可能會(huì)影響整個(gè)團(tuán)隊(duì)的工作,這需要考慮類的OCP原則(開(kāi)放封閉原則,也就是哪些對(duì)外部開(kāi)放,哪些不對(duì)外開(kāi)放)。
- SV允許使用 randomize() with來(lái)增加額外的約束,這和在類里增加約束是等效的,但同時(shí)要注意類內(nèi)部約束和外部約束之間應(yīng)該是協(xié)調(diào)的,如果出現(xiàn)違背,隨機(jī)數(shù)會(huì)求解失敗(求解失敗,不同的工具報(bào)告形式不同,有的是error,有的是warning)。
class packet;rand int length;constraint c_short {soft length inside {[1:32];}}
endclass//------------------------packet p;
initial beginp =new ();assert(p.randomize() with {length inside {[36:46];};length != 40; });transmit(p);
end
上述例子中randomize() with{}約束與c_short產(chǎn)生可沖突,那會(huì)不會(huì)報(bào)錯(cuò)呢?
答案是不會(huì),因?yàn)閏_short約束前加了soft(軟約束)關(guān)鍵字,意義就在于當(dāng)外部或子類的約束發(fā)生沖突時(shí),其優(yōu)先級(jí)降低,不會(huì)影響外部或子類的約束。
隨機(jī)函數(shù)
pre_randomize 和 post_randomize
-
有時(shí)需要在調(diào)用randomize()之前或之后立即執(zhí)行一些操作,例如在隨機(jī)前設(shè)置一些非隨機(jī)變量(上下限、條件值、權(quán)重),或者在隨機(jī)化后需要計(jì)算數(shù)據(jù)的誤差、分析和記錄隨機(jī)數(shù)據(jù)等。
-
SV提供兩個(gè)預(yù)定義的void類型函數(shù)pre_randomize和post_randomize,用戶可以類中定義這兩個(gè)函數(shù),分別在其中定義隨機(jī)化前的行為和隨機(jī)化后的行為。
-
如果某個(gè)類中定義了pre_randomize或post_randomize,那么對(duì)象在執(zhí)行randomize()之前或之后會(huì)分別執(zhí)行這兩個(gè)函數(shù),所以pre_randomize和post_randomize可以看做是randomize函數(shù)的回調(diào)函數(shù)(callback function)。
和之前學(xué)的語(yǔ)言類的知識(shí)關(guān)聯(lián)起來(lái)了,好像spring框架的前置和后置
系統(tǒng)隨機(jī)數(shù)函數(shù)
SV提供了一些常用的系統(tǒng)隨機(jī)函數(shù),這些系統(tǒng)隨機(jī)函數(shù)可以直接調(diào)用來(lái)返回隨機(jī)數(shù)值:
- $random()平均分布,返回32位有符號(hào)隨機(jī)數(shù)。
- $urandom()平均分布,返回32位無(wú)符號(hào)隨機(jī)數(shù)。
- $urandom_range()在指定范圍內(nèi)的平均分布。
隨機(jī)化個(gè)別變量
- 在調(diào)用randomize()時(shí)可以傳遞變量的一個(gè)子集,這樣只會(huì)隨機(jī)化類里的幾個(gè)變量。
- 只有參數(shù)列表里的變量才會(huì)被隨機(jī)化,其他變量會(huì)被當(dāng)做狀態(tài)量而不會(huì)被隨機(jī)化。
- 所有的約束仍然保持有效。
- 注意:類里所有沒(méi)有被指定rand的變量也可以作為randomize()的參數(shù)而被隨機(jī)化。
- 注意:未進(jìn)行隨機(jī)化的變量默認(rèn)初始值為0。
class rising;byte low;rand byte med, hi;constraint up {low<med; med<hi;}
endclass//----------------------------------initial beginrising r;r =new();r.randomize(); //隨機(jī)化hi和med,不改變lowr.randomize(med); //只隨機(jī)化medr.randomize(low); //只隨機(jī)化low
end
數(shù)組約束
約束數(shù)組的大小
- 在約束隨機(jī)標(biāo)量的同時(shí),我們也可以對(duì)隨機(jī)化數(shù)組進(jìn)行約束。
- 多數(shù)情況下,數(shù)組的大小應(yīng)該給定范圍,防止生成過(guò)大體積的數(shù)組或空數(shù)組。
- 此外,還可以在約束中結(jié)合數(shù)組的其他方法sum(), product(), and(), or(), 和xor()。
class dyn_size;rand logic [31:0] d[];constraint d_size {d,size() inside {[1:10];};}
endclass
約束數(shù)組的元素
- SV可以利用foreach對(duì)數(shù)組每一個(gè)元素進(jìn)行約束,和直接寫(xiě)出對(duì)固定大小數(shù)組的每一個(gè)元素相比,foreach更簡(jiǎn)潔。
- 針對(duì)動(dòng)態(tài)數(shù)組,foreach更適合于對(duì)非固定大小數(shù)組中每個(gè)元素的約束。
class good_sum5;rand uint len[];constraint c_len{foreach (len[i]) len[i] inside {[1:255]};len.sum() < 1024;len.size() inside {[1:8]};}
endclass
產(chǎn)生唯一元素值的數(shù)組
如果想要產(chǎn)生一個(gè)隨機(jī)數(shù)組,它的每一個(gè)元素值都是唯一的,如果使用randc數(shù)組,數(shù)組中的每一個(gè)元素只會(huì)獨(dú)立的隨機(jī)化,并不會(huì)按照我們期望的使得數(shù)組中的元素值是唯一的。
解決方案1:
rand bit [7:0] data;
constraint c_data{foreach(data[i])foreach(data[j])if(i != j) data[i] != data[j];
}
解決方案2:
class randc_data;randc bit [7:0] data[64];
endclassclass data_array;bit [7:0] data_array [64];function void pre_randomize();randc_data rcd;rcd = new();foreach (data_array[i]) beginassert(rcd.randomize());data_array[i] = rcd.val;endendfunction
endclass
“randc”關(guān)鍵詞表示周期性隨機(jī),即所有可能的值都賦過(guò)值后隨機(jī)才可能重復(fù),也就好比54張撲克牌抽牌游戲,rand代表每抽完一張放回去才可以下次抽牌,randc代表沒(méi)抽完一張不需要放回就抽取下一張,如果抽完了,那就全部放回再次同樣規(guī)則抽取。
- 特別示例如下,首先“<=”代表小于等于,其次限定da.size為(3/4/5),實(shí)際不可能取到5,原因是da.size的約束體現(xiàn)在“da[i] <= da[i+1]”時(shí),約束的是i和i+1為(3/4/5)。
rand bit [7:0] da[];
constraint c_da {da.size() inside {[3:5]};foreach(da[i]) da[i] <= da[i+1];
}
隨機(jī)化句柄數(shù)組
-
隨機(jī)句柄數(shù)組的功能是在調(diào)用其所在類的隨機(jī)函數(shù)時(shí),隨機(jī)函數(shù)會(huì)隨機(jī)化數(shù)組中的每一個(gè)句柄所指向的對(duì)象。因此隨機(jī)句柄數(shù)組的聲明一定要添加rand來(lái)表示其隨機(jī)化的屬性,同時(shí)在調(diào)用隨機(jī)函數(shù)前要保證句柄數(shù)組中的每一個(gè)句柄元素都是非懸空的,這需要早隨機(jī)化之前為每一個(gè)元素句柄構(gòu)建對(duì)象。
-
如果要產(chǎn)生多個(gè)隨機(jī)對(duì)象,那么你可能需要建立隨機(jī)句柄數(shù)組。和整數(shù)數(shù)組不同,你需要在隨機(jī)化前分配所有的元素,因?yàn)樵陔S機(jī)求解器不會(huì)創(chuàng)建對(duì)象。使用動(dòng)態(tài)數(shù)組可以按照需要分配最大數(shù)量的元素,然后再使用約束減小數(shù)組的大小。在隨機(jī)化時(shí),動(dòng)態(tài)句柄數(shù)組的大小可以保持不變或減小,但不能增加。
parameter MAX_SIZE = 10;
class RandStuff;bit[1:0] value = 1;
endclassclass RandArray;rand RandStuff array[];constraint c_array {array.size() inside {[1:MAX_SIZE]};}function new();//分配最大容量array = new[MAX_SIZE];foreach (array[i]) array[i] = new();endfunction
endclass//---------------------------RandArray ra;
initial begin// 構(gòu)造數(shù)組和所有對(duì)象ra = new();// 隨機(jī)化數(shù)組,但可能會(huì)減小數(shù)組assert(ra.randomize());foreach(ra.array[i]) $display(ra.array[i].value);
end
- 問(wèn)題1:執(zhí)行ra.randomize() with {array.size=2}時(shí),array[0].value 和 array[0].value分別是多少?
答案都是1,首先value沒(méi)有加rand,所以randomize不會(huì)隨機(jī)value,仍然保持為1。
- 問(wèn)題2:為什么要分配最大容量?
答案是只有創(chuàng)建對(duì)象,并且分配最大容量,才能保證隨機(jī)化時(shí)可能會(huì)碰到句柄數(shù)組懸空,無(wú)指向?qū)ο?#xff0c;隨機(jī)會(huì)報(bào)錯(cuò)。
- 總結(jié):句柄數(shù)組的隨機(jī),首先查看句柄指向的對(duì)象內(nèi)有沒(méi)有rand變量,其次對(duì)句柄數(shù)組按最大容量進(jìn)行例化。
隨機(jī)控制
- 產(chǎn)生事務(wù)序列的另一個(gè)方法是使用SV的randsequence結(jié)構(gòu)。這對(duì)于隨機(jī)安排組織原子(atomic)測(cè)試序列很有幫助。
initial beginfor (int i=0; i<15; i++) beginrandsequence (stream)stream: cfg_read := 1 | //權(quán)重不一樣io_read := 2 | //權(quán)重不一樣mem_read := 5; //權(quán)重不一樣cfg_read: (cfg_read_task;) |(cfg_read_task;) cfg_read;mem_read: (mem_read_task;) |(mem_read_task;) mem_read;io_read: (io_read_task;) |(io_read_task;) io_read;endsequenceend
end
這是一個(gè)偽代碼或特定于某個(gè)工具(如SystemVerilog)的代碼片段,用于描述一種隨機(jī)序列生成機(jī)制。我會(huì)逐步解釋這段代碼的含義。
-
initial begin
initial 是 SystemVerilog 中的一個(gè)塊,它在仿真開(kāi)始時(shí)就執(zhí)行一次。begin … end 是定義該塊范圍的關(guān)鍵詞。 -
- for (int i=0; i<15; i++) begin … end
這是一個(gè)循環(huán)結(jié)構(gòu),它將執(zhí)行其內(nèi)部的代碼塊 15 次。每次迭代,i 的值從 0 增加到 14。
-
- randsequence (stream)
randsequence 是 SystemVerilog 中用于描述隨機(jī)序列的關(guān)鍵字。它允許用戶為某個(gè)事件流(在這里是 stream)定義多個(gè)可能的隨機(jī)序列。
-
- stream: cfg_read := 1 | io_read := 2 | mem_read := 5;
這定義了三個(gè)事件:cfg_read、io_read 和 mem_read,并分別為它們分配了權(quán)重。權(quán)重決定了這些事件在隨機(jī)選擇時(shí)出現(xiàn)的頻率。例如,mem_read 事件出現(xiàn)的頻率是 cfg_read 的 5 倍,是 io_read 的 2.5 倍。
-
- cfg_read: (cfg_read_task;) | (cfg_read_task;) cfg_read;
這定義了當(dāng) cfg_read 事件被選擇時(shí)要執(zhí)行的任務(wù)或操作。這里,cfg_read_task 被執(zhí)行,然后事件流可以選擇再次進(jìn)入 cfg_read 狀態(tài)(通過(guò)后面的 cfg_read)或者退出這個(gè)狀態(tài)(因?yàn)橛袃蓚€(gè)選擇,但只執(zhí)行一個(gè))。
-
- mem_read: (mem_read_task;) | (mem_read_task;) mem_read;
與 cfg_read 類似,但這里是為 mem_read 事件定義的行為。
-
- io_read: (io_read_task;) | (io_read_task;) io_read;
同樣,這是為 io_read 事件定義的行為。
- 總結(jié):
這段代碼描述了一個(gè)循環(huán),該循環(huán)運(yùn)行 15 次。在每次迭代中,它都會(huì)根據(jù)定義的權(quán)重隨機(jī)選擇一個(gè)事件(cfg_read、io_read 或 mem_read)并執(zhí)行相應(yīng)的任務(wù)。
每個(gè)事件都有自己的任務(wù)(cfg_read_task、mem_read_task 和 io_read_task),并且在任務(wù)執(zhí)行完畢后,可以選擇再次進(jìn)入相同的事件或退出。
這種隨機(jī)性在模擬或測(cè)試復(fù)雜系統(tǒng)的行為時(shí)非常有用,因?yàn)樗梢阅M多種可能的執(zhí)行順序或條件。
- 我們也可以使用randcase來(lái)建立隨機(jī)決策樹(shù),但它帶來(lái)的問(wèn)題是沒(méi)有變量可供追蹤調(diào)試。
initial beginint len;randcase:1: len = $urandom_range(0,2); //10%8: len = $urandom_range(3,5); //80%1: len = $urandom_range(6,7); //10%endcase$display("len=%0d", len);
end
- 總結(jié):
- randsequence和randcase是針對(duì)輕量級(jí)的隨機(jī)控制的應(yīng)用。而我們可以通過(guò)定義隨機(jī)類取代上述隨機(jī)控制的功能,并且由于類的繼承性使得后期維護(hù)代碼時(shí)更加方便。
- randsequence的相關(guān)功能我們?cè)趨f(xié)調(diào)激勵(lì)組件和測(cè)試用例時(shí),可能會(huì)用到。
- randcase則對(duì)應(yīng)著隨機(jī)約束中的dist權(quán)重約束 + if-else條件約束的組合。
參考資料
- Wenhui’s Rotten Pen
- SystemVerilog
- chipverify