在Testbench中很可能需要文件的读写操作,在可综合的设计中也可能会用到文件写入。SystemVerilog/Verilog提供的文件写入读取方法并不多,主要有两类。
第一类是writememb/writememh/readmemb/readmemh,第二类是$fscanf/$fwrite。第一类用法简单,但是功能弱,文件读取也不支持多维数组;第二类用法复杂一点,功能相对强大,配合循环语句可以处理多维数组。
writemem[b|h]主要有以下用法:
(1)$readmemb("<数据文件名>",<存储器名>);
(2)$readmemb("<数据文件名>",<存储器名>,<起始地址>);
(3)$readmemb("<数据文件名>",<存储器名>,<起始地址>,<终止地址>);
其中起始地址和终止地址都是相对于“存储器名”指定的数据而言,而不是指写入文件时的位置。参考以下代码。
parameter WIDTH = 8;
parameter INDEX0 = 16;
parameter FILE_PATH_B = "E:/FPGA/PRACTICE/FileReadWrite/files/file_b.txt";
parameter FILE_PATH_H = "E:/FPGA/PRACTICE/FileReadWrite/files/file_h.txt";
parameter FILE_PATH_F = "E:/FPGA/PRACTICE/FileReadWrite/files/file_f.txt";
parameter FILE_PATH_HALF= "E:/FPGA/PRACTICE/FileReadWrite/files/file_half.txt";
reg [WIDTH-1: 0] dat0[INDEX0-1: 0], dat1[INDEX0-1: 0];
wire [WIDTH-1: 0] dat1_comp[INDEX0-1: 0];
reg [WIDTH-1: 0] dat0_read[INDEX0-1: 0];
integer i, j;
integer fid;
initial begin
for( i=0; i
$writememb( FILE_PATH_B, dat0, 0 )将以二进制的格式写入数据,如下图所示。每个数据占据一行。注意,使用writememb写入的文件也要通过readmemb读出,否则数据可能是错误的。
$writememb( FILE_PATH_B, dat0, 0 )将以二进制的格式写入数据。
$writememh( FILE_PATH_HALF, dat0, INDEX0/2 )将从dat0[8]开始按照十六进制写入数据,如下图所示。
$readmemb和$reamdmemh可以从文件中读取数据,其用法如下。
(1)$readmem[b|h]("<数据文件名>",<存储器名>);
(2)$readmem[b|h]("<数据文件名>",<存储器名>,<起始地址>);
(3)$readmem[b|h]("<数据文件名>",<存储器名>,<起始地址>,<终止地址>);
其中起始地址是指从数据文件中读取的数据将从“存储器名”的指定地址开始填充,参考上文程序中的以下语句。
$readmemh( FILE_PATH_H, dat0_read, INDEX0/2 );
for( i=0; i 从FILE_PATH_H中读取的数据将从dat0_read的地址INDEX0/2的位置开始填充,而dat0_read中未初始化且未填充的数据为“x”,如下图所示。 注意,readmem[b|h]是将数据放在存储器中,所以dat0_read应该定义为reg型,而不是wire。 此外,readmem[b|h]是不能填充二维数据的。比如reg [M:N] dat[X:Y]是可以使用readmem[b|h]填充的,而reg [M:N] dat[X:Y] [A:B]是不可以用作readmem[b|h]的操作对象的。 这两个系统函数的功能更强大,参考以下代码。 上述代码首先对dat1进行赋值,注意dat1[INDEX0-1]被单独赋值,且其值包括“x”。通过$fopen打开或新建一个可写的文本文件,将每两个连续的数据写入文件。如下图所示。 通过$fwrite(fid, "%d %d\n", dat1[i*2], dat1[i*2+1])将dat1按照十进制的格式写入文件,每两个数据为一行。$fwrite函数会自动换行,所以上述代码中的\n是多余的。后续代码通过$fscanf将数据从文件中读出,可以每次读出一个数据,也可以每次读出多个数据。 注意,写入文件格式和读出格式必须匹配,否则读出数据出错。比如按照十进制写入,就需要按照十进制读出。 $fscanf和c语言中的printf的使用方法基本一致。 dat1[INDEX0-1]中的一个bit包含x,所以整个数据存储为x。 $fwrite和$fscanf可以支持多维数组读写。写入函数不再赘述,主要描述读出操作,参考以下代码。 上述代码展示了如何通过for循环从文件中读出数据并填充多维数组的,可以一次读出一个数据,也可以读出多个,比如$fscanf(fid, "%h %h", dat2_comp[i][j*2], dat2_comp[i][j*2+1])。下一句将读出数据打印出来。注意文件数据类型要和读出类型一致。 2. $fwrite和$fscanf
2.1 基本用法
initial begin
for( i=0; i
2.2 多维数据读写
parameter INDEX1 = 4;
parameter INDEX2 = 4;
parameter FILE_PATH_2D_B = "E:/FPGA/PRACTICE/FileReadWrite/files/file_2D_b.txt";
parameter FILE_PATH_2D_H = "E:/FPGA/PRACTICE/FileReadWrite/files/file_2D_h.txt";
reg [WIDTH-1: 0] dat2[INDEX1-1: 0] [INDEX2-1: 0];
wire [WIDTH-1: 0] dat2_comp[INDEX1-1: 0] [INDEX2-1: 0];
initial begin
for( i=0; i