转载https://blog.csdn.net/lbt_dvshare/article/details/132004995
Verilog 提供了很多对文件进行操作的系统任务。经常使用的系统任务主要包括:
- 文件开、闭:
$fopen
, $fclose
, $ferror
- 文件写入:
$fdisplay
, $fwrite
, $fstrobe
, $fmonitor
- 字符串写入:
$sformat
, $swrite
- 文件读取:
$fgetc
, $fgets
, $fscanf
, $fread
- 文件定位:
$fseek
, $ftell
, $feof
, $frewind
- 存储器加载:
$readmemh
, $readmemb
使用文件操作任务(尤其注意 $sforamt
, $gets
, $sscanf
等)对文件进行操作时,需要根据文件性质和变量内容确定使用哪一种系统任务,并保证参数及读写变量类型与文件内容的一致性,不要将字符串类型和多进制类型相混淆。
文件open/close
系统任务 | 调用格式 | 任务描述 |
---|---|---|
文件打开 | fd = $fopen("fname", mode) ; | fname 为打开文件的名字 fd 为返回的 32bit 文件描述符 --- 正确打开时,fd 为非零值 --- 打开出错时,fd为零值 mode 用于指定文件打开的方式 |
文件关闭 | $fclose(fd) ; | 关闭 fd 描述的对应文件 |
文件错误 | err = $ferror(fd, str) ; | 正常打开文件时: --- err 与 str 均为零值, 打开文件出错时: --- err 返回非零值表示错误 --- str 返回非零值存储错误类型 --- 官方建议 str 长度为 640bit 位宽 |
-
integer fd1, fd2 ;
-
integer err1, err2 ;
-
reg [
320:
0] str1, str2 ;
//错误类型的变量也可以为可支持的 string 类型
-
initial begin
-
//existing file
-
fd1 = $
fopen(
"./DATA_RD.HEX",
"r");
//打开存在的文件
-
err1 = $
ferror(fd1, str1);
-
$
display(
"File1 descriptor is: %h.", fd1 );
//非零值
-
$
display(
"Error1 number is: %h.", err1 );
//0
-
$
display(
"Error2 info is: %s.", str1 );
//0
-
$
fclose(fd1);
-
//not existing file
-
fd2 = $
fopen(
"../../FILE_NOEXIST.HEX",
"r");
//打开的文件不存在
-
err2 = $
ferror(fd2, str2);
-
$
display(
"File2 descriptor is: %h.", fd2 );
//0
-
$
display(
"Error2 number is: %h.", err2 );
//非零值
-
$
display(
"Error2 info is: %s.", str2 );
//非零值
-
$
fclose(fd2);
-
end
运行结果:
fd = $fopen("fname", mode) 中 mode 类型及其描述如下:
r | 只读打开一个文本文件,只允许读数据。 |
---|---|
w | 只写打开一个文本文件,只允许写数据。如果文件存在,则原文件内容会被删除。如果文件不存在,则创建新文件。 |
a | 追加打开一个文本文件,并在文件末尾写数据。如果文件如果文件不存在,则创建新文件。 |
rb | 只读打开一个二进制文件,只允许读数据。 |
wb | 只写打开或建立一个二进制文件,只允许写数据。 |
ab | 追加打开一个二进制文件,并在文件末尾写数据。 |
r+ | 读写打开一个文本文件,允许读和写 |
w+ | 读写打开或建立一个文本文件,允许读写。如果文件存在,则原文件内容会被删除。如果文件不存在,则创建新文件。 |
a+ | 读写打开一个文本文件,允许读和写。如果文件不存在,则创建新文件。读取文件会从文件起始地址的开始,写入只能是追加模式。 |
rb+ | 读写打开一个二进制文本文件,功能与 "r+" 类似。 |
wb+ | 读写打开或建立一个二进制文本文件,功能与 "w+" 类似。 |
ab+ | 读写打开一个二进制文本文件,功能与 "a+" 类似。 |
文件写入
调用格式 | 任务描述 |
---|---|
$fdisplay(fd, arguments) ; | 按顺序或条件写文件,自动换行 |
$fwrite(fd, arguments) ; | 按顺序或条件写文件,不自动换行 |
$fstrobe(fd, arguments) ; | 语句执行完毕后选通写文件 |
$fmonitor(fd, arguments) ; | 只要数据有变化就写文件 |
-
integer fd ;
-
integer err, str ;
-
initial begin
-
fd = $
fopen(
"./DATA_RD.HEX",
"a+");
//末尾追加的方式打开
-
err = $
ferror(fd, str);
-
if (!err) begin
-
$
fdisplay(fd,
"New data1: %h", fd) ;
-
$
fdisplay(fd,
"New data2: %h", str) ;
-
$
fdisplay(fd,
"New data3: %h", err) ;
-
//$write(fd, "New data3: %h", err) ; //最后一行不换行打印
-
end
-
$
fclose(fd);
-
end
文件读取
系统任务 | 调用格式及说明 |
---|---|
按字符读文件 | c = $fgetc( fd ) ; 按字符格式将 fd 数据输出给变量 c,c 位宽最少为 8 读取错误时 c 值为 EOF(-1),可以用 $ferror 检查错误类型 |
按字符写缓冲区 | code = $ungetc(c, fd ) ; 向文件 fd 缓冲区写字符 c c 值在下次调用 $fgetc 时返回,文件 fd 自身内容不会发生变化 正常写缓冲时返回值 code 为 0,发生错误时返回值 code 为 EOF |
按行读文件 | code = $fgets(str, fd) 按字符连续读,直至变量 str 被填满,或一行内容读取完毕,或文件结束 正常读取时返回值 code 为读取行数(次数),发生错误时 code 为 0 |
按格式读文件 | code = $fscanf(fd, format, args) ; 按格式 format 将文件 fd 中的数据读取到变量 args 中 format 可参考 $display 指定格式说明 读取一次的停止条件为空格或换行 读取发生错误时返回值 code 为 0 |
按格式读字符串 | code = $sscanf(str, format, args) ; 按格式 format 将字符串型变量 str 读取到变量 args 中 调用格式方法和 $fscanf 一致 |
按二进制读文件 | code = $fread(store, fd, start, count) ; 按二进制数据流格式将数据从文件 fd 读取到数组或寄存器变量 store 中 start 为文件起始地址,count 为读取长度 若 start/count 未指定,数据会全部填充至变量 store 中 若 store 为寄存器类型,则 start/count 参数无效,store 变量填充满一次数据后便会停止读取 |
$fgetc 例子
-
integer i ;
-
reg [
31:
0] char_buf ;
-
initial begin
-
#
30 ;
-
fd = $
fopen(
"DATA_RD.HEX",
"r");
-
$
write(
"Read char: ");
-
err = $
ferror(fd, str);
-
if (!err)
begin
-
for (i=0; i<13; i++) begin
-
char_buf[7:0] = $
fgetc(fd) ;
//按单个字符读取
-
$
write(
"%c", char_buf[
7:
0]) ;
//不换行逐次打印单个字符
-
end
-
$
write(
".\n") ;
-
end
-
end
$fgets 例子
-
integer fd ;
-
integer code ;
-
reg [
99:
0] line_buf [
9:
0] ;
-
initial begin
-
#
31 ;
-
fd = $
fopen(
"DATA_RD.HEX",
"r");
-
err = $
ferror(fd, str);
-
if (!err)
begin
-
for
(i=0; i<6; i++) begin
//按字符串格式逐行读取
-
code = $
fgets(line_buf[i], fd) ;
//末尾含"\n",将打印2行
-
$
display(
"Get line data%d: %s", i, line_buf[i]) ;
-
end
-
end
-
//十六进制显示,将显示对应的 ASCIII 码字
-
$
display(
"Show hex line data%d: %h",
2, line_buf[
2]) ;
-
$
display(
"Show hex line data%d: %h",
4, line_buf[
4]) ;
-
$
fclose(fd) ;
-
end
$fscanf
-
reg [
31:
0] data_buf [
9:
0] ;
-
reg [
63:
0] string_buf [
9:
0] ;
-
reg [
31:
0] data_get ;
-
reg [
63:
0] data_test ;
-
-
initial begin
-
-
fd = $
fopen(
"DATA_RD.HEX",
"r");
-
err = $
ferror(fd, str);
-
if (!err)
begin
-
for
(i=0; i<4; i++) begin
-
//前4行数据按照十六进制读取和显示
-
code = $
fscanf(fd,
"%h", data_buf[i]);
-
$
display(
"$fscanf read data%d: %h", i, data_buf[i]) ;
-
end
-
for
(i=4; i<6; i++) begin
-
//后2行数据按照字符串类型读取和显示
-
code = $
fscanf(fd,
"%s", string_buf[i]);
-
$
display(
"$fscanf read data%d: %s", i, string_buf[i]) ;
-
end
-
end
-
end
文件定位
系统任务 | 调用格式 | 任务描述 |
---|---|---|
获取文件位置 | pos = $ftell( fd ) ; | 返回文件当前位置距离文件首部的偏移量,初始地址为 0 偏移量按照字节为一单位(8bits) 配合 $fseek 使用 |
重定位 | code = $fseek(fd, offset, type) ; | 设置文件下一个输入或输出的位置 offset 为设置的偏移量 type 为偏移量的操作类型 --- 0: 设置位置到偏移地址 --- 1: 设置位置到当前位置加偏移量 --- 2: 设置位置到文件尾加偏移量,经常使用负数来表示文件尾向前的偏移量 |
无偏移重定位 | code = $rewind( fd ) ; | 等价于 $fseek( fd, 0, 0) ; |
判断文件尾部 | code = $feof(fd) ; | 判读是否到文件尾部 检测到文件尾部时返回值为 1,否则为 0 |
-
reg [
31:
0] data4 ;
//寄存器变量长度为 4bytes
-
reg [
199:
0] str_long ;
-
integer pos ;
-
initial begin
-
#
40 ;
-
fd = $
fopen(
"DATA_RD.HEX",
"r");
-
err = $
ferror(fd, str);
-
if (!err) begin
-
//first read
-
code = $
fscanf(fd,
"%h", data4);
//从0位置开始读
-
pos = $
ftell(fd);
//读8byte后位置为8,坐标为(0,8)
-
$
display(
"Position after read: %d", pos) ;
-
$
display(
"1st read data: %h", data4) ;
-
-
//type = 0
-
code = $
fseek(fd,
4,
0) ;
//从位置4、坐标(0,4)开始读
-
code = $
fscanf(fd,
"%h", data4);
//读到换行符停止
-
pos = $
ftell(fd);
//读4byte后位置为8,坐标为(0,8)
-
$
display(
"type 0: current position: %d", pos) ;
-
$
display(
"type 0: read data: %h", data4) ;
-
//type = 1
-
code = $
fseek(fd,
4,
1) ;
//从位置4+9=12、坐标(1,3)据开始读
-
code = $
fscanf(fd,
"%h", data4);
//读到换行符停止
-
pos = $
ftell(fd);
//读5byte后位置为17,坐标为(1,8)
-
$
display(
"type 1: current position: %d", pos) ;
-
$
display(
"type 1: read data: %h", data4) ;
-
//type = 2
-
code = $
fseek(fd, -(
96
-31),
2) ;
//从位置31、坐标(3,4)开始读
-
code = $
fscanf(fd,
"%h", data4);
-
pos = $
ftell(fd);
//读4byte后位置为35,坐标为(3,8)
-
$
display(
"type 2: current position: %d", pos) ;
-
$
display(
"type 2: read data: %h", data4) ;
-
-
//rewind read
-
code = $
rewind(fd) ;
//重新将文件指针的位置指向文件首部
-
pos = $
ftell(fd);
//此时位置为 0
-
$
display(
"Position after $rewind: %d", pos) ;
-
//read all content of file
-
while (!$
feof(fd)) begin
-
code = $
fgets(str_long, fd);
-
$
write(
"Read : %s", str_long) ;
-
end
-
$
fclose(fd) ;
-
end
-
end
加载存储器
系统任务 | 调用格式及说明 |
---|---|
加载十六进制文件 | $readmemh("fname", mem, start_addr, finish_addr) |
fname 为数据文件名字 mem 为数组型/存储器型变量 start_addr、finish_addr 分别为起始地址和终止地址 start_addr、finish_addr 可以省略,此时加载数据的停止条件为存储器变量 mem 被填充完毕,或文件读取完毕 文件内容只应该有空白符(或换行、空格符)、二进制或十六进制数据 注释用"//"进行标注,数据间建议用换行符区分 | |
加载二进制文件 | $readmemb("fname", mem, start_addr, finish_addr) |
用法格式同 $readmemb |
</article>