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數字系統設計教程》夏宇聞
轉載請註明出處,謝謝。