1. 程式人生 > 其它 >《SystemVerilog驗證測試平臺編寫指南》學習筆記——連線設計和測試平臺(二)

《SystemVerilog驗證測試平臺編寫指南》學習筆記——連線設計和測試平臺(二)

技術標籤:SystemVerilog

一、介面的驅動和取樣

測試平臺需要驅動和取樣設計的訊號,主要是通過帶有時鐘塊的介面做到的。非同步訊號通過介面時沒有任何延時,比如rst,而時鐘塊中的訊號將得到同步。

1、介面同步

可以使用Verilog的@和wait來同步測試平臺中的訊號

訊號同步

program automatic test(bus.if.TB bus);
	initial begin
		@bus.cb;		//在時鐘塊的有效時鐘沿繼續
		repeat (3) @bus.cb;		//等待三個有效時鐘沿
		@bus.cb.grant;		//在任何邊沿繼續
		@(postedge bus.cb.grant);		//上升沿繼續
		@(negegde bus.cb.grant);		//下降沿繼續
		wait(bus.cb.grant == 1);		//等待表示式被執行,如果已經是真,不做任何延時
		@(postedge bus.cb.grant or negedge bus.rst)		//等待幾個訊號
	end
endprogram

2、介面訊號取樣

模組中同步介面的取樣和驅動

'timescale 1ns/1ns
program test(arb_if.TEST arbif);
	initial begin
		$monitor("@%0t: grant=%h", $time, arbif.cb.grant);
		# 50ns $display("End of test");
endprogram

module arb(arb_if.DUT arbif);
	initial begin
		# 7 arbif.grant = 1; 	//@7ns;
		# 10 arbif.grant =
2; //@17ns; # 8 arbif.grant = 3; //@25ns; end endmodule

波形如下:
在這裡插入圖片描述
波形表明,arbif.cb.grant在時鐘邊沿到來之前獲得數值,在5ns時獲取的值時之前的X值,所以5ns~15ns顯示的值為X,在15ns時獲取的值時15ns到來之前的值1,所以15ns ~ 25ns顯示的值為1,以此類推。
arb模組在一個時鐘週期的中間產生grant訊號的值1和2,然後在時鐘沿產生值3。

3、介面訊號驅動

使用帶有時鐘塊介面的測試平臺

program automatic test(arb_if.TEST arbif);

	initial begin
		arbif.
cb.request <= 2'b01; //在時鐘塊中使用modport的時候,任何同步介面訊號都必須加上介面名和時鐘塊名的字首 $display("@%0t: Drove req = 01", $time); repeat(2) @arbif.cb; if(arbif.cb.grant != 2'b01) $display("@%0t: al: grant != 2'b01", $time); end endprogram : test

4、通過時鐘塊驅動介面訊號

在時鐘塊中應當使用同步驅動,即“<=”操作符來驅動訊號。訊號在賦值後並不會立即改變——別忘了測試平臺在Reactive區域執行而設計的程式碼在Active區域執行。如果在時鐘沿之間產生一個request訊號,那麼該變化知道下一個時鐘沿才會傳遞給設計。因此驅動總是同步的。
如果測試平臺在時鐘的有效沿驅動同步介面訊號,其值會立即傳遞到設計中,這是因為時鐘塊的預設輸出延時是# 0。

驅動一個同步介面

program test(arb_if.TEST arbif);
	initial begin
		# 7 arbif.cb.request <= 3; 	//@7ns;
		# 10 arbif.cb.request <= 2; 	//@17ns;
		# 8 arbif.cb.request <= 1; 	//@25ns;
		# 15 finish;
	end;
endprogram

module arb(arb_if.DUT arbif);
	initial
		$monitor("@%0t: req=%h", $time, arbif.request);

波形圖如下:在這裡插入圖片描述
這裡注意看波形中在一個週期中即5 ~ 15ns中,第7ns時TEST產生的值3,在下一個週期也就是15ns~25ns時被DUT捕獲輸出。但是為什麼TEST在17ns產生的值2沒有被DUT捕獲輸出呢?那是因為之前說的**如果測試平臺在時鐘的有效沿驅動同步介面訊號,其值會立即傳遞到設計中,這是因為時鐘塊的預設輸出延時是# 0。**也就是說TEST在17ns時產生的值2不會立即傳遞給設計,會在下一個時鐘沿傳遞給設計。但是DUT在25ns時準備捕獲TEST的值時,TEST又在25ns上升沿驅動同步訊號讓值變為了1,此時值會立即傳遞到設計中,相當於值2被值1“覆蓋”了,所以DUT捕獲到了值1沒有捕獲到值2。

非同步地驅動時鐘塊訊號會導致數值丟失,應該使用時鐘延時字首以保證在時鐘UA沿驅動訊號。

# # 2 arbif.cb.request <= 0;		//等待兩個時鐘週期然後賦值,只能在時鐘塊裡作為驅動訊號的字首來使用,因為它需要知道使用哪個時鐘來做延時
# # 3;		//非法,必須跟賦值語句同時使用

5、介面中的雙向訊號

在程式中對線網(net)賦值的時候,SystemVerilog實際上將值寫到了一個驅動該線網的臨時變數中。所有驅動器輸出的值經過判決後,程式可以直接通過連線讀取該值。

程式和介面中的雙向訊號

interface master_if(input bit clk);
	wire[7:0] data;		//雙向訊號
	clocking cb @(postedge clk);
		inout data;
	endclocking
	
	modport TEST(clocking cb);
endinterface

program test (master_if mif);
	initial begin
		mif.cb.data <= 'z;		//三態匯流排
		@mif.cb;
		$displayh(mif.cb.data);		//從匯流排讀取
		mif.cb.data <= 7'h5a;		//驅動匯流排
		@mif.cb;
		mif.cb.data <= 'z;		//釋放匯流排
	end
endprogram		

6、為什麼在程式中不允許使用always塊

program中可以使用initial塊但是不允許使用always塊。因為SystemVerilog程式比由許多並行執行的塊構成的Verilog更加接近C程式,它擁有一個(或者多個)程式入口。在一個設計中,一個always塊可能從模擬的開始就會在每一個時鐘的上升沿觸發執行,但是一個測試平臺的執行過程是經過初始化、驅動、響應設計行為等步驟後結束模擬的。在這裡一個連續執行的always模組不能正常工作。但是可以使用initial forever來替代always塊。

7、時鐘發生器

時鐘發生器應當定義成一個模組,不應該把時鐘發生器放在程式塊裡。功能驗證關心的是在正確的時鐘週期內提供正確的值,而不是納秒級的延時和時鐘的相對偏移。

模組中的時鐘發生器

module clock_generator(output bit clk);
	initial
		always # 5 clk = ~clk;		//在時間0之後生成時鐘沿
endmodule

二、將這些模組都連線起來

編譯器不會成功編譯任何一個在埠列表中含有介面的模組或程式塊。

含有介面的模組

//沒有介面宣告,該模組不會被正確編譯,必須完成介面的連線工作
module uses_an_interface(arb_ifc.DUT ifc);
	initial ifc.grant = 0;
endmodule

連線DUT和介面的頂層模組

module top;
	bit clk;
	always # 10 clk = !clk;
	arb_ifc ifc(clk);		//帶有時鐘塊的介面
	uses_an_interface ul(ifc);		//必須這樣定義才能被編譯
endmodule

三、頂層作用域

編譯單元,它是一起編譯的原始檔的一個組合。任何module,macromodule,interface,program,package或者primitive邊界之外的作用域被稱為編譯單元作用域,也稱為$unit

仲裁器設計的頂層作用域

'timescale 1ns/1ns
parameter int TIMEOUT = 1000000;
const string time_out_msg = "ERROR: Time Out!";

module top;
	test t1();
endmodule

program automatic test;
	...
	initial begin
		# TIMEOUT;
		$display("%s", time_out_msg);
		$finish;
	end
endprogram

例項名$root允許從頂層作用域開始明確地引用系統中的成員名。可以指定絕對路徑或者相對路徑來明確地引用跨模組的變數。

四、程式——模組互動

程式塊可以讀寫模組中的所有訊號,但是模組卻看不到程式塊。程式可以呼叫模組中的例程來執行不同的動作,這個例程可以改變訊號的值,也稱為後門。