1. 程式人生 > >Verilog部分系統函式用法

Verilog部分系統函式用法

ISE與ModelSim聯合模擬時,在模擬檔案中如何讀取txt文件資料和寫入txt文件。

一、讀取txt文件資料

在Verilog HDL程式中有兩個系統任務$readmemb和$readmemh用來從檔案中讀取資料到存貯器中。這兩個系統任務可以在模擬的任何時刻被執行使用,其使用格式共有以下六種:
1) $readmemb("<資料檔名>",<存貯器名>);
2) $readmemb("<資料檔名>",<存貯器名>,<起始地址>);
3) $readmemb("<資料檔名>",<存貯器名>,<起始地址>,<結束地址>);
4) $readmemh("<資料檔名>",<存貯器名>);
5) $readmemh("<資料檔名>",<存貯器名>,<起始地址>);
6) $readmemh("<資料檔名>",<存貯器名>,<起始地址>,<結束地址>);

在這兩個系統任務中,被讀取的資料檔案的內容只能包含:空白位置(空格,換行,製表格(tab)和form-feeds),註釋行(//形式的和/*...*/形式的都允許),二進位制或十六進位制的數字。數字中不能包含位寬說明和格式說明,對於$readmemb系統任務,每個數字必須是二進位制數字,對於$readmemh系統任務,每個數字必須是十六進位制數字。數字中不定值x或X,高阻值z或Z,和下劃線(_)的使用方法及代表的意義與一般Verilog HDL程式中的用法及意義是一樣的。另外數字必須用空白位置或註釋行來分隔開。

在下面的討論中,地址一詞指對存貯器(memory)建模的陣列的定址指標。當資料檔案被讀取時,每一個被讀取的數字都被存放到地址連續的存貯器單元中去。

存貯器單元的存放地址範圍由系統任務宣告語句中的起始地址和結束地址來說明,每個資料的存放地址在資料檔案中進行說明。當地址出現在資料檔案中,其格式為字元“@”後跟上十六進位制數。如:
                                                                           @hh...h
對於這個十六進位制的地址數中,允許大寫和小寫的數字
。在字元“@”和數字之間不允許存在空白位置。可以在資料檔案裡出現多個地址。當系統任務遇到一個地址說明時,系統任務將該地址後的資料存放到存貯器中相應的地址單元中去。

舉例說明:

先定義一個有256個地址的位元組存貯器 mem:
                                                                  reg[7:0] mem[1:256];
下面給出的系統任務以各自不同的方式裝載資料到存貯器mem中。
initial $readmemh("mem.data",mem);
initial $readmemh("mem.data",mem,16);
initial $readmemh("mem.data",mem,128,1);
第一條語句在模擬時刻為0時,將裝載資料到以地址是1的存貯器單元為起始存放單元的存貯器中去。第二條語句將裝載資料到以單元地址是16的存貯器單元為起始存放單元的存貯器中去,一直到地址是256的單元為止。第三條語句將從地址是128的單元開始裝載資料,一直到地址為1的單元。在第三種情況中,當裝載完畢,系統要檢查在資料檔案裡是否有128個數據,如果沒有,系統將提示錯誤資訊。

應用說明:

此部分為自己的例項。

 reg  [7:0]  my_mem [0:65535];//定義一個有65536個地址的位元組存貯器
 $readmemh("128by512_init.txt", my_mem);//將txt文件中的資料儲存到my_mem中

txt文件中的格式說明,因為使用readmemh讀取資料,所以文件中的數字為十六進位制,一個數據一行。

二、寫入txt資料

integer fouti;
fouti = $fopen("result.txt");//寫入文件
$fwrite(fouti, "%d", data_out, "\n");//寫入資料

(1)fwrite是需要觸發條件的,在一次觸發條件之後也不會自動發生換行,所以要求手動新增換行。

(2)如果寫入資料的格式為%d,則認為是無符號數。

三、$display和$write任務

格式:

$display(p1,p2,....pn);
$write(p1,p2,....pn);

這兩個函式和系統任務的作用是用來輸出資訊,即將引數p2到pn按引數p1給定的格式輸出。引數p1通常稱為“格式控制”,引數p2至pn通常稱為“輸出表列”。這兩個任務的作用基本相同。$display自動地在輸出後進行換行,$write則不是這樣。如果想在一行裡輸出多個資訊,可以使用$write。在$display和$write中,其輸出格式控制是用雙引號括起來的字串,它包括兩種資訊:

(1)格式說明,由"%"和格式字元組成。它的作用是將輸出的資料轉換成指定的格式輸出。格式說明總是由“%”字元開始的。對於不同型別的資料用不同的格式輸出。表一中給出了常用的幾種輸出格式。

(2)普通字元,即需要原樣輸出的字元。其中一些特殊的字元可以通過表二中的轉換序列來輸出。下面表中的字元形式用於格式字串引數中,用來顯示特殊的字元。

在$display和$write的引數列表中,其“輸出表列”是需要輸出的一些資料,可以是表示式。下面舉幾個例子說明一下。

[例1]:

module disp;
    initial
        begin
            $display("\\\t%%\n\"\123");
        end
endmodule

輸出結果為

\%
"S

從上面的這個例子中可以看到一些特殊字元的輸出形式(八進位制數123就是字元S)。

[例2]:

module disp;
    reg[31:0] rval;
    pulldown(pd);
    initial
        begin
            rval=101;
            $display("rval=%h hex %d decimal", rval, rval);
            $display("rval=%o otal %b binary", rval, rval);
            $display("rval has %c ascii character value",rval);
            $display("pd strength value is %v",pd);
            $display("current scope is %m");
            $display("%s is ascii value for 101",101);
            $display("simulation time is %t",$time);
        end
endmodule

其輸出結果為:

rval=00000065 hex 101 decimal
rval=00000000145 otal 00000000000000000000000001100101 binary
rval has e ascii character value
pd strength value is StX
current scope is disp
e is ascii value for 101
simulation time is 0

四、系統任務$finish

格式:

$finish;
$finish(n);

系統任務$finish的作用是退出模擬器,返回主作業系統,也就是結束模擬過程。任務$finish可以帶引數,根據引數的值輸出不同的特徵資訊。如果不帶引數,預設$finish的引數值為1。下面給出了對於不同的引數值,系統輸出的特徵資訊:

0 不輸出任何資訊

1 輸出當前模擬時刻和位置

2 輸出當前模擬時刻,位置和在模擬過程中所用memory及CPU時間的統計

五、系統任務$stop

格式:

$stop;
$stop(n);

$stop任務的作用是把EDA工具(例如模擬器)置成暫停模式,在模擬環境下給出一個互動式的命令提示符,將控制權交給使用者。這個任務可以帶有引數表示式。根據引數值(0,1或2)的不同,輸出不同的資訊。引數值越大,輸出的資訊越多。

六、應用例項

module main_test;

	// Inputs
	reg all_clk_50M;
	reg all_RSTn;

	reg [7:0] my_mem [0:65535];
	reg [13:0] pix_cnt;   
	reg [16:0] save_cnt;
	reg [63:0] data_in;
	integer fouti;
	// Outputs
	wire [7:0] data_out;
	wire wr_done_sig;
	wire save_done_sig;

	// Bidirs
	wire [63:0] data_inout;

	// Instantiate the Unit Under Test (UUT)
	main uut (
		.all_clk_50M(all_clk_50M), 
		.all_RSTn(all_RSTn), 
		.data_inout(data_inout), 
		.data_out(data_out), 
		.wr_done_sig(wr_done_sig), 
		.save_done_sig(save_done_sig), 
	);

	initial begin
		// Initialize Inputs
		all_clk_50M = 0;
		all_RSTn = 1;
        fouti = $fopen("medfilter2_re.txt");
		$readmemh("743_128by512_init.txt", my_mem);
		// Wait 100 ns for global reset to finish
		#100;
        all_RSTn = 0;
		// Add stimulus here
		#100;
		pix_cnt = 1;
		save_cnt = 1;
		data_in = {my_mem[0],my_mem[1],my_mem[2],my_mem[3],my_mem[4],my_mem[5],my_mem[6],my_mem[7]};
		// Add stimulus here

	end
	/*******************************************************************************/	
	assign data_inout = 1 ? data_in : 64'hzzz ;

	always #10 all_clk_50M = ~all_clk_50M;
	//寫入資料的過程
	/*******************************************************************************/
	[email protected](posedge all_clk_50M)
		begin
			if(wr_done_sig)
				begin
				 pix_cnt <= pix_cnt + 1;
				 data_in = {my_mem[pix_cnt*8],my_mem[pix_cnt*8+1],my_mem[pix_cnt*8+2],my_mem[pix_cnt*8+3],my_mem[pix_cnt*8+4],my_mem[pix_cnt*8+5],my_mem[pix_cnt*8+6],my_mem[pix_cnt*8+7]};
				end
		end
	[email protected](posedge all_clk_50M)
		begin
			if(wr_done_sig)
				begin
				    $display("pix_cnt = %d",pix_cnt);
				end
		end
	//輸出結果的過程
	/*******************************************************************************/
	[email protected](posedge all_clk_50M)
		begin
			if(save_done_sig)
				save_cnt <= save_cnt + 1;
		end
	/*******************************************************************************/
	[email protected](posedge all_clk_50M)
		begin
			if(save_done_sig)
				begin
				    $fwrite(fouti, "%d", data_out, "\n");
				    $display("save_cnt = %d",save_cnt);
				end
		end
	/*******************************************************************************/
	[email protected](posedge all_clk_50M)
		begin
			if(save_cnt == 17'd65537)
				begin 
				    $display("Image Completed!\n");
				    $display("The all time is %d \n",$time);
				    $stop;
				end
		end
endmodule

參考資料:《Verilog數字系統設計教程》夏宇聞

轉載請註明出處,謝謝。