verilog系統任務讀寫文件$fopen和$fdisplay的使用 $monitor 使用體會


幾個簡單的系統任務,$readmemb,$readmemh,$fopen,$fdisplay;基本上就可以完成對文件的讀寫操作。

一、讀任務
在verilog語言中有兩個系統任務$readmemb,$readmemh可以用來從文件中讀取數據到存儲器中。這兩個任務可以在仿真的任何時刻被執行使用,其使用方法如下: $readmemb
1,$readmemb("<數據文件名(路徑地址和文件名)>",<存儲器名>);
2, $readmemb("<數據文件名>",<存儲器名>,<起始地址(存儲器的地址)>);
3, $readmemb("<數據文件名>",<存儲器名>,<起始地址>,<結束地址>);
$readmemh
4,$readmemh("<數據文件名(路徑地址和文件名)>",<存儲器名>);
5, $readmemh("<數據文件名>",<存儲器名>,<起始地址(存儲器的地址)>);
5, $readmemh("<數據文件名>",<存儲器名>,<起始地址>,<結束地址>);
這里需要注意的是:
1,存儲器的空間要足夠,如設定[7:0] remember[0:15];即是初始化了一個15個字長為8位的存儲器;
2,文件中的數據是一次讀到寄存器中的,仿真中通常使用數據文件來做信號源。並且讀數據總是從文件起始地址讀到結束地址結束,存儲器容量要足夠;
3,文件應為標准數據文件,如果文件只存放數據就默認第一個數據地址為初始地址;若第一個數據設定
@002
11111111 10101011
@004
10xz0011 1100101x
第0,和第1個數據沒有寫,系統讀進存儲器時默認為 xxxx_xxxx;
4,文件若只寫文件名需要將文件放置在默認文件路徑下,可以通過modelsim->file->changedirectory來更改。
二、寫任務
這里寫任務用$fopen和$fdisplay兩個系統任務完成,其中前者用來得到文件句柄,所謂句柄就是用來打開這個文件的讀寫通道,這里筆者在modelsim環境下試驗了一下一旦用$fopen打開文件就會將文件清空。因此要讀文件最好用$readmemb任務,寫文件再用$fopen,注意最好新建個新文件來寫,以免重要數據被清空。
用$fopen取得想要寫文件的句柄handle,然后我們desc=handle|1;(目的最低位置1)這樣寫文件時trancript框中也同樣會輸出;
用$fdisplay(desc,"display=%b",remember[k]);通過for語句就可以將原文件中的數據寫到另一個文件中去了;
例子如下:
module rewr_test();
reg [7:0]mem[0:15];
integer k,handle2,desc;
initial
begin
handle2=$fopen("file2.dat");
$readmemb("file1.dat",mem);
desc=handle2 |1;
$display("handle2=%b desc=%b",handle2,desc);
for(k=0;k<=15;k=k+1)
begin
$fdisplay(desc,"%b",mem[k]);
end
end
endmodule


handle2是文件句柄,打開第一個文件句柄值為32‘h0000_0002;desc最后一位置1,transcript對話框中也有相應輸出,打開文件發現file1.dat和file2.dat兩文件一致。

1.$fopen打開文件

用法1.$fopen("<文件名>");
用法2.<文件句柄>=$fopen("<文件名>");
注意:用$fopen打開文件會將原來的文件清空,若要讀數據就用$readmemb,$readmemh就可以了,這個語句不會清空原來文件中的數據。
用$fopen的情況是為了取得句柄,即文件地址,也就是寫文件時用$fdisplay(desc,"display1");時才用。
用法1自然無須多解釋,對於用法2,句柄就是任務$fopen返回的多通道描述符,默認為32位,最低位(第0位)默認被設置1,默認開放標准輸出通道,即transcript窗口。
module disp;
integer handle1,handle2,handle3;
initial
begin
handle1=$fopen("file1.dat");
handle2=$fopen("file2.dat");
handle3=$fopen("file3.dat");
$display("%h %h %h",handle1,handle2,handle3);
end
endmodule
輸出
handle1=32‘h0000_0002
handle2=32'h0000_0004
handle3=32'h0000_0008
即對每一次使用$fopen函數后都打開了一個新的通道,並且返回了一個設置為1的位相對應。默認應該是0001,以上每調用分別設置為0010 ,0100,1000(只考慮最低四位)。
這個句柄對我們非常有用,因為在寫文件時會用到。
2.寫文件我們用到系統任務$fdisplay,$fwrite.
兩者用法相似,前者寫完就會自動換行,后者不會換行。
用法:$fdisplay(<文件描述符(句柄,用於確定是寫哪一個文件)>,p1,p2(寫入內容));
描述符是很有意思的(默認為32位),如上我們知道,文件句柄最多只能有一個1,但是描述符可以是有多個1,哪一個位上有1,就同時在這些位對應的輸出文件上寫文件。因此可以同時寫多個文件。
只考慮后四位情況:
1,0001時,只進行在transcript對話框中的輸出,
2,0101時,即對file2文件寫又在transcript框輸出、
3,1111時,對全部文件寫,同時在transcript框輸出。
由於每個句柄只有一個位置上是1,因此我們想在哪些文件中同時輸出我們就可以用以下語句來寫
desc=handleI | handleK | handleM | handleN | 1(一般與1或,最低位置1再transcript框輸出。)
一個例子如下:
module disp;
integer handle1,handle2,handle3;
integer desc1,desc2,desc3;
initial
begin
handle1=$fopen("file1.dat");
handle2=$fopen("file2.dat");
handle3=$fopen("file3.dat");
$display("%h %h %h",handle1,handle2,handle3);
desc1=handle1|1;
$fwrite(desc1,"display 1");
$fmoniter(desc1,"display 1");
$fstrobe(desc1,"display 1");

desc2=handle2|handle1|1;
$fdisplay(desc2,"display 2");
desc3=handle3|1;
$fdisplay(32'd15,"display 3");
end
endmodule
$monitor系統任務提供了監控和輸出參數列表中的表達式和變量值的功能,其參數列表中輸出控制格式字符串和輸出表列的規則和$display一樣, 當啟動一個帶有一個或多個參數的$monitor任務時,每當參數列表中的變量或表達式的值發生變化時整個參數列表中變量或表達式的值都將輸出顯示。 如果同一時刻有兩個或多個表達式的值發生變化,只輸出一次。 參數可以是$time,用於標明變化時刻。
如$monitor ($time,,"rxd=%b txd=%b",rxd,txd);這里的“,,”用來表示空格參數在輸出時顯示為空格
 
$monitor的打開和關閉分別用$monitoron和$monitoroff表示,用來控制任務的啟動和停止,使得很容易控制任務何時發生,何時結束。
$monitor用於initial塊中,只要不調用$monitoroff,該任務就可以不間斷的對所設定信號進行監視。
例子如下(對一個4位加法計數器counter信號進行監控):
`timescale 1ns/1ns
module moni_test();
reg[3:0]counter;
reg clk;
reg rst;
initial
begin
rst=0;
#10 rst=1;
$monitor ($time,,"counter=%d",counter);
$monitoron;
end
initial
begin
clk=0;
forever #5 clk=~clk;
end
always@(negedge rst or posedge clk)
if(!rst)
counter<=4'd0;
else
counter<=counter+1;
endmodule

主要觀察transcript對話框,可見每經過10ns,counter就會變化一次,此時參量時間也會輸出。
注意1. 僅監測$time是不會每次都輸出的,必須是除了時間之外的參量變化才可以做到參量變化就輸出
2 .,,符號輸出的是一個空格符,輸出結果中得到了驗證。

幾個簡單的系統任務,$readmemb,$readmemh,$fopen,$fdisplay;基本上就可以完成對文件的讀寫操作。

一、讀任務
在verilog語言中有兩個系統任務$readmemb,$readmemh可以用來從文件中讀取數據到存儲器中。這兩個任務可以在仿真的任何時刻被執行使用,其使用方法如下: $readmemb
1,$readmemb("<數據文件名(路徑地址和文件名)>",<存儲器名>);
2, $readmemb("<數據文件名>",<存儲器名>,<起始地址(存儲器的地址)>);
3, $readmemb("<數據文件名>",<存儲器名>,<起始地址>,<結束地址>);
$readmemh
4,$readmemh("<數據文件名(路徑地址和文件名)>",<存儲器名>);
5, $readmemh("<數據文件名>",<存儲器名>,<起始地址(存儲器的地址)>);
5, $readmemh("<數據文件名>",<存儲器名>,<起始地址>,<結束地址>);
這里需要注意的是:
1,存儲器的空間要足夠,如設定[7:0] remember[0:15];即是初始化了一個15個字長為8位的存儲器;
2,文件中的數據是一次讀到寄存器中的,仿真中通常使用數據文件來做信號源。並且讀數據總是從文件起始地址讀到結束地址結束,存儲器容量要足夠;
3,文件應為標准數據文件,如果文件只存放數據就默認第一個數據地址為初始地址;若第一個數據設定
@002
11111111 10101011
@004
10xz0011 1100101x
第0,和第1個數據沒有寫,系統讀進存儲器時默認為 xxxx_xxxx;
4,文件若只寫文件名需要將文件放置在默認文件路徑下,可以通過modelsim->file->changedirectory來更改。
二、寫任務
這里寫任務用$fopen和$fdisplay兩個系統任務完成,其中前者用來得到文件句柄,所謂句柄就是用來打開這個文件的讀寫通道,這里筆者在modelsim環境下試驗了一下一旦用$fopen打開文件就會將文件清空。因此要讀文件最好用$readmemb任務,寫文件再用$fopen,注意最好新建個新文件來寫,以免重要數據被清空。
用$fopen取得想要寫文件的句柄handle,然后我們desc=handle|1;(目的最低位置1)這樣寫文件時trancript框中也同樣會輸出;
用$fdisplay(desc,"display=%b",remember[k]);通過for語句就可以將原文件中的數據寫到另一個文件中去了;
例子如下:
module rewr_test();
reg [7:0]mem[0:15];
integer k,handle2,desc;
initial
begin
handle2=$fopen("file2.dat");
$readmemb("file1.dat",mem);
desc=handle2 |1;
$display("handle2=%b desc=%b",handle2,desc);
for(k=0;k<=15;k=k+1)
begin
$fdisplay(desc,"%b",mem[k]);
end
end
endmodule


handle2是文件句柄,打開第一個文件句柄值為32‘h0000_0002;desc最后一位置1,transcript對話框中也有相應輸出,打開文件發現file1.dat和file2.dat兩文件一致。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM