SystemVerilog允许我们读写磁盘中的文件。
如何打开和关闭文件?
可以使用**$ fopen()系统任务打开文件以进行读取或写入。 该任务将返回称为文件描述符的32位整数句柄。** 在关闭该文件之前,应使用该句柄对其进行读写操作。 可以使用**$ fclose()系统任务关闭文件描述符**。 文件描述符关闭后,不允许对其进行进一步的读取或写入。
例
在下面显示的代码中,我们将声明一个名为fd的int变量来保存文件描述符。 fd最初为零,并从$ fopen()获取有效值,可以检查该文件是否成功打开。 最后,在执行$ fclose()时关闭文件。
module tb;
initial begin
// 1. Declare an integer variable to hold the file descriptor
int fd;
//2.在当前文件夹中以“读取”权限打开一个名为“ note.txt”的文件。如果该文件不存在,则fd将为零
fd = $fopen ("./note.txt", "r");
if (fd) $display("File was opened successfully : %0d", fd);
else $display("File was NOT opened successfully : %0d", fd);
// 2.在具有“写”权限的当前文件夹中打开一个名为“ note.txt”的文件,“ fd”现在指向同一文件,但处于写模式
fd = $fopen ("./note.txt", "w");
if (fd) $display("File was opened successfully : %0d", fd);
else $display("File was NOT opened successfully : %0d", fd);
// 3. Close the file descriptor
$fclose(fd);
end
endmodule
Simulation Log
ncsim> run
Open failed on file "./note.txt". No such file or directory
File was NOT opened successfully : 0
File was opened successfully : -2147483645
ncsim: *W,RNQUIE: Simulation is complete.
在模拟结束之前关闭所有打开的文件以将内容完全写入文件中非常重要。
如何在读取和追加模式下打开?
默认情况下,以写w模式打开文件。通过提供正确的模式类型,也可以在其他模式下打开文件。下表显示了可以打开文件的所有不同模式。
Argument | Description |
---|---|
“r” | 读文件 |
“w” | 创建用于写入,如果存在则覆盖 |
– | – |
“a” | 文件不存在创建,已经存在则否则追加;在文件末尾的写入 |
“r+” | 开放更新(读写) |
– | – |
“w+” | 截断或创建更新 |
“a+” | 为EOF的更新添加、打开或创建 |
– | – |
例
在下面的代码中,我们将看到如何使用上表中所述的不同文件访问模式。
module tb;
initial begin
int fd_w, fd_r, fd_a, fd_wp, fd_rp, fd_ap;
fd_w = $fopen ("./todo.txt", "w"); //在写入模式下打开一个新文件,并将文件描述符存储在fd_w中
fd_r = $fopen ("./todo.txt", "r"); // 以读取模式打开
fd_a = $fopen ("./todo.txt", "a"); //以追加模式打开
if (fd_w) $display("File was opened successfully : %0d", fd_w);
else $display("File was NOT opened successfully : %0d", fd_w);
if (fd_r) $display("File was opened successfully : %0d", fd_r);
else $display("File was NOT opened successfully : %0d", fd_r);
if (fd_a) $display("File was opened successfully : %0d", fd_a);
else $display("File was NOT opened successfully : %0d", fd_a);
// Close the file descriptor
$fclose(fd_w);
$fclose(fd_r);
$fclose(fd_a);
end
endmodule
从下面的日志中可以看到,所有三个变量都有一个不同的值,并且每个变量都指向同一文件,但是具有不同的访问权限。
Simulation Log
ncsim> run
ncsim: *W,VFOPTW: File ./todo.txt being opened by Initial stmt (file: ./testbench.sv, line: 2 in worklib.tb [module]) has been opened earlier.
File was opened successfully : -2147483645
File was opened successfully : -2147483644
File was opened successfully : -2147483643
ncsim: *W,RNQUIE: Simulation is complete.
如何读写文件?文件应该在写w模式下打开,或者附加一个模式。可以使用$ fdisplay()和$ fwrite()等系统任务将格式化字符串写入文件。这些任务的第一个参数是文件描述符句柄,第二个参数是要存储的数据。要读取文件,必须以读r模式或读写r+模式打开它。$fgets()是一个系统任务,它将从文件中读取一行。如果这个任务被调用10次,那么它将读取10行。
例
下面显示的代码演示了如何使用$ fdisplay()打开文件并将内容写入文件。 然后以读取模式打开文件,并使用$ fgets()将内容读回到本地变量中。 然后使用标准显示任务$ display()将其打印出来。
module tb;
int fd; // Variable for file descriptor handle
string line; // String value read from the file
initial begin
// 1. Lets first open a new file and write some contents into it
fd = $fopen ("trial", "w");
// Write each index in the for loop to the file using $fdisplay
// File handle should be the first argument
for (int i = 0; i < 5; i++) begin
$fdisplay (fd, "Iteration = %0d", i);
end
// Close this file handle
$fclose(fd);
// 2. Let us now read back the data we wrote in the previous step
fd = $fopen ("trial", "r");
// Use $fgets to read a single line into variable "line"
$fgets(line, fd);
$display ("Line read : %s", line);
// Get the next line and display
$fgets(line, fd);
$display ("Line read : %s", line);
// Close this file handle
$fclose(fd);
end
endmodule
Simulation Log
ncsim> run
Line read : Iteration = 0
Line read : Iteration = 1
ncsim: *W,RNQUIE: Simulation is complete.
如何读取直到文件结尾?
在前面的示例中,我们两次使用$ fgets()系统任务从文件中读取两行。 SystemVerilog还有另一个名为$ feof()的任务,该任务在到达文件末尾时返回true。 可以按如下所示在循环中使用它来读取文件的全部内容。
Example
module tb;
int fd; // Variable for file descriptor handle
string line; // String value read from the file
initial begin
// 1. Lets first open a new file and write some contents into it
fd = $fopen ("trial", "w");
for (int i = 0; i < 5; i++) begin
$fdisplay (fd, "Iteration = %0d", i);
end
$fclose(fd);
// 2. Let us now read back the data we wrote in the previous step
fd = $fopen ("trial", "r");
while (!$feof(fd)) begin
$fgets(line, fd);
$display ("Line: %s", line);
end
// Close this file handle
$fclose(fd);
end
endmodule
Simulation Log
ncsim> run
Line: Iteration = 0
Line: Iteration = 1
Line: Iteration = 2
Line: Iteration = 3
Line: Iteration = 4
Line:
ncsim: *W,RNQUIE: Simulation is complete.
如何解析一行的值?
SystemVerilog还有另一个名为$ fscanf()的系统任务,它使我们可以扫描并获取某些值。
Example
module tb;
int fd; // Variable for file descriptor handle
int idx;
string str;
initial begin
// 1. Lets first open a new file and write some contents into it
fd = $fopen ("trial", "w");
for (int i = 0; i < 5; i++)
$fdisplay (fd, "Iteration = %0d", i);
$fclose(fd);
// 2. Let us now read back the data we wrote in the previous step
fd = $fopen ("trial", "r");
// fscanf returns the number of matches
while ($fscanf (fd, "%s = %0d", str, idx) == 2) begin
$display ("Line: %s = %0d", str, idx);
end
// Close this file handle
$fclose(fd);
end
endmodule
Simulation Log
ncsim> run
Line: Iteration = 0
Line: Iteration = 1
Line: Iteration = 2
Line: Iteration = 3
Line: Iteration = 4
ncsim: *W,RNQUIE: Simulation is complete.
参考文献:
【1】https://www.chipverify.com/systemverilog/systemverilog-file-io