文章目录
$fdisplay, $fwrite,$fstrobe,$fmonitor
在这篇文章(Verilog的系统任务----$readmemh和$readmemb)中,介绍了Verilog的系统任务$readmemh和$readmemb的用法,利用这两个系统任务,可以实现从文件中读取数据到仿真中数组的功能。
无独有偶,有时候在仿真时,我们同样需要将获取的数据写入文件中,以便后续的分析和利用。下面这三类系统任务可以用来实现对文件的写入操作:
系统任务$fopen可以用来打开指定的文件(以便后续对其进行写入操作),其返回值为integer变量,表示当前文件的句柄值,获取句柄值后,后续就可以根据句柄值对不同的文件进行写入操作。即
integer handle1; //定义句柄1
handle1 = $fopen("file_name",type) //以指定类型(type)的方式来打开文件,并将其返回值赋给handle1
type指定了打开文件的类型,可以是以下种类:

通常情况下,我们使用 w 来作为类型值,即以对一个ASCII文本文件进行写操作的方式来打开该文件 (txt)。
比如,我们在如下路径新建一个TXT文件file_test1.txt:

然后就可以用下述的方法将其打开:
integer handle1; //定义句柄1
handle1 = $fopen("D:/file_test/file_test1.txt","w"); //以w类型(写)的方式来打开文件,并将其返回值赋给handle1
这4个函数都可以对指定文件进行打印或写入操作,其用法与对应的$display, $write,$strobe,$monitor几乎一致。建议参考:Verilog中的系统任务(显示/打印类)--$display, $write,$strobe,$monitor_孤独的单刀的博客-CSDN博客_verilog打印Verilog中的系统任务(显示/打印类)--$display, $write,$strobe,$monitorhttps://wuzhikai.blog.csdn.net/article/details/125340502 区别在于$display等函数是直接在仿真中进行打印,而$fdisplay等函数是对指定文件进行打印,需要通过句柄来指定是对具体哪个文件进行操作。如:
//指定句柄并打开文件
reg data;
integer handle1; //定义句柄1
handle1 = $fopen("D:/file_test/file_test1.txt","w"); //以w类型(写)的方式来打开文件,并将其返回值赋给handle1
//对指定文件写入数据
$fdisplay(handle1,"%d\n",data); //按照十进制格式写入数据到handle1对应的文件中,只能逐个写入
$fclose系统任务用来关闭指定文件,关闭后即无法对该文件进行操作。其格式如下:
$fclose(handle1); //关闭文件file_test1,至此文件操作结束
首先新建两个TXT文件来后续对其写入数据,其名称和路径如下:

然后,编写一个testbench实现以下功能:
- `timescale 1ns / 1ns
-
- module file_test();
-
- reg [3:0] cnt1; //计数器1
- reg [3:0] cnt2; //计数器2
- reg clk; //主时钟
- reg rst_n; //复位
-
- integer handle1; //定义文件1句柄
- integer handle2; //定义文件2句柄
-
- //初始化赋值
- initial begin
- clk <= 1'b0;
- rst_n <= 1'b0;
- #20
- rst_n <= 1'b1;
- #200
- $finish;
- end
-
- //打开文件1、文件2
- initial begin
- handle1 = $fopen("D:/file_test/file_test1.txt","w");
- handle2 = $fopen("D:/file_test/file_test2.txt","w");
- end
-
- //计数器1从0000-1111循环计数
- always @(posedge clk or negedge rst_n) begin
- if(rst_n == 1'b0)
- cnt1 <= 4'b0000;
- else
- cnt1 <= cnt1 + 1'b1;
- end
-
- //计数器2从1111-0000循环计数
- always @(posedge clk or negedge rst_n) begin
- if(rst_n == 1'b0)
- cnt2 <= 4'b1111;
- else
- cnt2 <= cnt2 - 1'b1;
- end
-
- //将计数器1的10个值打印到文件1
- always @(posedge clk or negedge rst_n) begin
- if(rst_n == 1'b0)
- ;
- else if(cnt1 >4'd9)
- $fclose(handle1);
- else
- $fdisplay(handle1,"%d",cnt1); //以10进制的方式将当前的cnt1的值写入文件1
- end
-
- //将计数器2的10个值打印到文件2
- always @(posedge clk or negedge rst_n) begin
- if(rst_n == 1'b0)
- ;
- else if(cnt2 <4'd6)
- $fclose(handle2);
- else
- $fdisplay(handle2,"%d",cnt2); //以10进制的方式将当前的cnt2的值写入文件2
- end
-
- always #10 clk = ~clk; //主时钟20ns
-
- endmodule
使用vivado自带仿真器进行仿真,仿真结束后,打开两个文本文件,观察其写入数据是否与预期一致。
文件1:依次写入0-9共10个数据

文件2:依次写入15-6共10个数据

对两个文件的数据写入均与预期设计一致。
参考资料1:IEEE Standard for Verilog® Hardware Description Language(IEEE Std 1364™-2005)