Verilog系列:【3】文件的IO操作
Abstract
Introduction
1 文件的打开与关闭
1.1 $fopen
格式:function integer fopen(string filename,string access_mode);
filename - 将要被操作的文件名
access_mode - 文件被访问的模式(如下表所示)
如果文件打开成功,则函数将返回一个32位整数的文件描述符,如果打开失败,那么将返回整数0.返回的32位描述符根据access_mode的有无又分为“File Descriptor”(有access_mode)和“Multi-Channel Descriptor” (无access_mode,此时默认文档处于可写状态)两种,且multichannel descriptor指示的32位数据可以进行逻辑操作后实现对多个文件的同时操作.
文件使用方式 | 说明 |
"r"或者"rb" | 为从文件读取数据打开一个文件 |
"w"或者"wb" | 创建一个输出文件,如果该文件存在的话则在创建新文件时删除原文件中的内容 |
"a"或者"ab" | 新写入文件的内容将附加在原文件的内容后 |
"r+","r+b"或者"rb+" | 对于已存在的文件既可以输入数据也可以输出数据,即更新 |
"w+","w+b"或者"wb+" | 新建一个文件,先向该文件写入数据,然后可进行读操作 |
"a+","a+b"或者"ab+" | 不删除原文件,新更新的内容将追加至原文件末尾 |
注意:
1>使用方式中"b"后缀表示进行操作的对象为二进制文件,但是在很多系统中对二进制并不去做区分;
1.2 $fclose
格式:task $fclose(integer file_descriptor);
1.3【示例】
仿真结果如下:
2.文件的读写
2.1常用输出函数
十进制格式 | 二进制格式 | 十六进制格式 | 八进制格式 |
$fdisplay | $fdisplayb | $fdisplayh | $fdisplayo |
$fwrite | $fwriteb | $fwriteh | $fwriteo |
$fstrobe | $fstrobeb | $fstrobeh | $fstrobeo |
$fmonitor | $fmonitorb | $fmonitorh | $fmonitoro |
2.2常用的格式字符
格式字符 | 说明 |
%h or %H | 以十六进制形式输出 |
%d or %D | 以十进制形式输出 |
%o or %O | 以八进制形式输出 |
%b or %B | 以二进制形式输出 |
%c or %C | 以ASCII字符的形式输出 |
%l or %L | 显示库的关联信息 |
%v or %V | 显示对应线网信号的强度 |
%m or %M | 显示层次路径 |
%s or %S | 以字符串形式输出 |
%t or %T | 以当前时间的格式显示 |
%u or %U | 以两值(1和0)形式输出数据 |
%z or %Z | 以四值(1、0、z、x)形式输出数据 |
%e or %E | 以指数形式显示实数 |
%f or %F | 以十进制形式显示实数 |
%g or %G | 选用%f或%e格式中输出宽度较短的一种形式 |
2.3格式化数据为指定字符串
2.3.1 $swrite
格式:
$swrite(output_reg,list_of_arguments);
2.3.2$sformat
格式:
$sformat(output_reg,format_string,list_of_arguments);
2.4 示例
仿真结果如下:
3.读文件操作
文件的读操作分为两种方式实现:文件句柄和直接读取.
3.1 $fgetc
格式:
char = $fgetc(fd);
3.2$fgets
格式:
integer code = $fgets(str,fd);
将从fd指定的文件读取一行字符并存储到str中,直到文件结束.如果读取失败,那么将会给code返回0,否则返回读取到的字符个数.
【示例】
仿真结果:
上述仿真结果为使用$fgetc单次读取一个字符的仿真结果:
上述仿真结果为使用$fgets单次读取一个字符串的仿真结果:
3.3 $fscanf和$sscanf
格式:
integer code = $fscanf(fd,format,args);
integer code =$sscanf(str,format,args);
按照format指定的格式从fd指定的文件中读取数据,并将读回的数据存储在args变量中,如果fd指向的文件的数据格式与format不相符,那么仿真将会异常.$sscanf功能与$fscanf功能类似,只是其将指定字符串内容读到了对应的args中.code指示了匹配format中指定格式的数据个数.如果参数个数不匹配,那么不匹配的参数将会被忽略,即返回值的个数以args为准.
【示例】
其中file1.dat和file2.dat的格式如下:
程序中fp3和fp1指向同一个数据文件,即file1.dat.仿真结果如下:
3.4 读取二进制数据
格式:
integer code = $fread(myreg,fd);
integer code = $fread(mem,fd);
integer code = $fread(mem,fd,start);
integer code =$fread(mem,fd,start,count);
integer code = $fread(mem,fd,,count);
该函数的主要功能是将fd指定的数据读取到指定的myreg或者mem(存储数据的数组)中,其中参数start和count即对mem对象使用.code返回当前已完成传输的字节数,如果读取出现异常,code将返回0.从文件读出的数据按照大端方式进行存取操作,即读取的高位数据将存储在高位数据段.读出的数据将按字节以ASCII的形式被读出,因此对于读回的数据需要对照ASCII码表进行分析.
【示例】
仿真结果:
19-23行执行后,file.dat中的所有数据将会按照顺序读取到对应的寄存器(my_reg)中并显示出来;
5-30行将file.dat中的所有数据一次性读取到定义的mem中,并将读取的数据存放到函数中指定起始位置开始存放,mem存取数据的个数由函数中指定的个数决定,仿真结果如下:
2-37行中的函数仅指定了数据存放在mem中的起始位置,那么函数执行时,将从该起始位置开始存放,指导指定的mem存放满或者file.dat中的数据完全读出.仿真结果如下:
9-44行,函数中仅指定了要被存放的数据的个数,那么函数执行时,将从数据文件中取出指定个数的数据,依次按照mem的起始地址开始存放.
4从文件给存储体加载数据
格式: $readmemb("file_name",memory_name[,start_addr[,finish_addr]]);
$readmemb("file_name",memory_name[,start_addr[,finish_addr]]);
这两个函数可以将指定文件的数据加载入指定的仿真模型存储空间中,并且可在仿真的任何阶段执行.其中可以被操作文件中仅能包含以下格式的信息:
-
空格(包括空格、换行等);
-
注释;
-
二进制或者十六进制格式的数据(数据可以不指定长度或者数据格式);
-
数据文件中表示地址的@和地址之间不能存在空格等;
这里需要注意数据文件中标识的地址必须在函数指定的地址参数范围之内;
$readmemb("file_name",memory_name[,start_addr[,finish_addr]]);
【示例】
读取的数据文件中存放数据为:
仿真结果如下:
20行执行之后,将会从存储体的起始地址(此处为0地址)开始存放从数据文件中读取到的数据,结果如下所示:
21行执行之后,将按照函数中指定的起始地址开始存放数据.仿真结果如下图:
22行执行结果如下图:
如果在数据文件中确实行号,那么缺失的地址在存储时将会被跳过,即存储体中对应该地址的内容将不会被更新.
当函数中起始地址省略,仅保留结束,那么数据文件中的数据将会从存储体起始地址开始存放直至该结束地址,存放结果如下图:
注意事项:
1)如果任务声明语句中和数据文件里都没有进行地址说明,则默认的存放起始地址为存储体定义语句的起始地址.数据文件里的数据被连续存放到该存储体中,指导存储体单元存满为止或数据文件里的数据被读取完.
2)如果任务中说明了存放的起始地址,没有说明存放的结束地址(数据文件里没有进行地址说明),则数据从起始地址开始存放,存放到该存储体定义语句中的结束地址为止.
3)如果任务在声明语句中起始地址和结束地址都进行了说明,则数据文件里的数据按该指定的起始地址开始存放,直到存放的数据被存放完毕,而不考虑该存储器定义语句中起始地址和结束地址.
4)如果地址信息在任务和数据文件中都进行了说明,那么数据文件里的地址必须在任务中地址参数声明的位置之内,否则将会得不到期望的结果.
5调试函数
格式:
integer flag = $feof(fd);
integer errno = $ferror(fd,str);
integer pos = $ftell(fd);
code = $fseek(fd,offset,operation);
code = $rewind(fd); // which is equivalent to $fseek(fd,0,0);
$fflush(mcd/fd);
$fflush();
5.1 $feof
5.2 $ferror
5.3$ftell
【示例】
仿真结果如下:
5.4 $fseek
$fseek允许对文件中的内容进行定位操作,这个操作将会改变下一个读取或写入操作的起始位置.
$fseek的参数说明如下:
Operation | 说明 |
0 | 从数据流的起始位置起offset个字节,offset必须是一个非负数 |
1 | 从数据流的当前位置起offset个字节,offset是一个可正可负的数 |
2 | 从数据流的尾部位置起offset个字节,offset是一个可正可负的数,如果为正值,将定位到文件尾的后面,即类似于附加 |
【示例】
其中通过$fwrite生成的数据如下:
仿真结果:
23行通过$sfseek将句柄指向重新定位到了文件中的156(可通过$ftell获得)位置,26行针对重新定位后的句柄指向对文件进行读访问操作,从仿真结果可以看出26行将会从文件的156位置开始记性读访问操作.
5.5 $fflush
在对文件进行写操作时,整个操作过程类似下图:
当程序执行过程中发生以下三种情况时,数据缓冲区中的数据会被写入到对应的文件中:
-
数据缓冲区满;
-
$fclose执行;
-
$fflush执行;
这里的$fflush函数可强迫将输出缓冲区中的内容写入到对应句柄指向的文件而无需等到$fclose的执行.$fflush在实际使用中存在三种格式:
$fflush(mcd); // 立即将缓冲区内容写入到对应的句柄指示的文件
$fflush(fd); // 立即将缓冲区内容写入到对应的句柄指示的文件
$fflush(); // 立即将缓冲区内容写入到所有打开的文件中
【示例】
Conclusion
在实际使用各种任务函数时,切记操作的数据格式以及生成的各种数据的格式,务必正确理解各种任务函数的使用方法,否则仿真结果可能与预期不相符.