Verilog常用的系统函数和任务(不定期更新)

我们在开发FPGA的过程中,特别是编写testbench时,经常会用到Verilog的系统函数,在查看Xilinx官方testbench或者大神写的testbench时,也会看到各种各样的系统函数,系统函数的特点就是前面带有$符号。灵活使用系统函数可以使得testbench的功能变得十分强大,然而大部分Verilog的中文教材介绍系统函数时都比较简略,这里我先提供IEEE的Verilog标准文档下载链接,在标准文档的第17章,会有所有系统函数的详细介绍,本篇会把最常用的系统函数做简单介绍,本篇会不定期更新。

一、文件操作

1、打开文件$fopen和关闭文件$fclose

文件打开进行读写操作之后记得一定要关闭,这点和其它所有编程语言都一样。

integer fp;

fp = $fopen("file_path/file_name","wb");

$fclose(fp);

$fopen的第一个参数是包含路径的文件名,这个路径可以是绝对路径,也可以是相对于当前文件夹(该条语句所在的文件所处的文件夹)的相对路径,如果打开的文件就在当前文件夹下,则可以直接写文件名,记得带后缀;第二个参数是打开类型,如果不填写,默认就是w,常见的打开类型如下表所示 ;返回值是一个多通道描述符(就是指针),由于Verilog没有指针变量,所以这里赋值给一个整型变量。

表1 文件打开类型常用参数
参数含义
r,w以文本方式进行读和写。文本方式会将一些特殊的数值,比如代表空格、换行、制表符等的ASCALL码值转换成空格、换行、制表符,这样子就容易出错,不推荐的方式。
a追加写,在文件的末尾写,否则就是从头覆盖。
rb,wb,ab以二进制的方式读、写、追加,此时没有特殊数值,不按照ASCALL码进行转换,推荐的方式。

 $fclose的参数就是$fopen返回的指针。r/w和rb/wb的不同请读者自己做做实验,如果本文的理解有误请读者朋友们在留言区指出。

2、写入文件:$fwrite,$fdisplay,$fmonitor,$fstrobe

这几个系统函数中最常用的是$fdisplay和$fwrite,这两个函数都是将变量(无论是阻塞赋值还是非阻塞赋值的变量)某一时刻(需要指定时刻)的值记录进文件中,用其中的任意一个都可以。

parameter mynum = 10000;

initial begin

    integer countnum;

    countnum = 0;

    while(countnum != mynum)  begin

         while(~dv)

             @(posedge clk);

         $fdisplay(fp,"%d", dout);//$fwrite(fp,"%d", dout);

         countnum = countnum + 1;

         @(posedge clk);

     end

end

上面这种写法很常见,意思是我们先指定一个文件存储的最大量,在dv有效的时间内,每一拍都存储dout的值,直到存到了最大量指定的个数。

$fdisplay的第一个参数就是文件指针;第二个参数是写入文件的格式,这里表示以十进制格式写入文件,类似于C语言中的printf函数指定的格式,$fdisplay可以自动换行,$fwrite则需写成“%d\n”;第三个参数是写入的变量。

$fmonitor表示只要变量发生变化就记录,三个参数和上面的意义一样,也可以自动换行。

$fmonitor(fp, "%format_char", parameter);

$fstrobe表示记录某一时刻的所有事件发生之后的变量值,也就是用非阻塞赋值的变量值,依然是三个参数,意义还是和上面的一样。

3、读取文件:$fread,$readmemb,$readmemh

如果用$fopen打开了文件,则使用$fread读取文件。

integer num;

num= $fread(mem,fp);

$fread的第一个参数mem是存储器或者寄存器;第二个参数是文件指针;返回值num是传入存储器的字符数,也就是读取的次数。每个字符的大小根据mem的位宽来决定(和mem的深度无关),如果mem的位宽是8位,则每个字符的大小就是一个字节,如果mem的位宽是32位,则每个字符的大小就是一个双字,如果文件读取错误,则返回0,如果mem的位宽不够宽,则将文件中的数据二进制转换之后舍去低位存入mem。(这里存疑,请读者朋友们帮忙看看是否正确。)

读取文件最常用的系统函数反而是$readmemb和$readmemh,用于给存储器初始化。

$readmemh("file_path/file_name",mem, 0,15);

$readmemb("file_path/file_name",mem);

$readmemb/h的第一个参数是包含路径的文件名,第二个参数是存储器名,第三个参数是存储器的起始地址,第四个参数是结束地址,后面两个参数可以省略,表示从首地址开始存储。

对于$readmemb,读取的文件中的每个数必须是二进制数,对于$readmemh,则必须是十六进制数。读取的文件中,数与数之间只能以空格、换行、制表符等空白符号隔开,可以用"//"注释,可以用x表示不定值,用z表示高阻值。

二、其它常见操作

1、控制台显示:$monitor,$write,$display

就是在modelsim的transcript窗口中打印出信息,和上面的写入文件的那几个系统函数类似,就是少了文件指针这个参数,所以不解释了。

$display("%d", dout);

2、随机数产生:$random

最常用的就是$random%n,表示产生0~n之间的随机数。

3、控制仿真过程:$finish,$stop

$finish表示结束当前仿真,$stop表示暂停当前仿真。

4、显示仿真时间刻度:$time,$realtime

$time返回整数时间值,$realtime返回实数时间值,都是相对于仿真开始时的仿真时间。这两个系统函数经常配合$display等使用。

$display($time,“ dout=%d”,dout);

输出为

#30 dout=200

需要注意的是,如果仿真精度不支持,比如`timescale 1ns/1ns,则$time和$realtime返回的时间值是一样的。


版权声明:本文为mikusic原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。