在进行Verilog仿真时往往需要从txt文件中读入待仿真的数据例如用于数字信号处理的波形数据用于加密算法的随机种子等。同时处理完成的数据往往又需要写入到txt文件中方便同软件算法的数据进行比较分析设计的正确性。下面总结了常用的读取和写入txt文件的常用方法。1、读取txt文件1.1 $readmemh和$readmemb用法按数据读取$readmemh和$readmemb的功能是将txt文件中的数据读取到reg数组中前者是按照16进制形式进行读取后者是按照2进制形式进行读取。一般的用法是在initial块中进行初始化读取后续需要使用数据直接通过reg数组使用数据。下面以$readmemh为例。首先在txt文件中1行中只放1个16进制数据下图以12bit的数据为例1024个数据就需要1024行中间不需要其他符号如下图所示。除了可以使用换行符作为相邻数据之间的分隔也可以使用空格进行分隔。其次申明一个reg数组12bit1024深度用于存放txt文件中的数据。最终在initial块中使用$readmemh将txt文件中的数据读入到reg数组中。值得注意的是 中的文件地址可以是绝对地址也可以是只有文件名sinewave_hex.txt但需要放在仿真文件夹下面例如vivado需要放在Project.sim\sim_1\behav\xsim。有时候绝对地址不好使的情况下可以只使用文件名然后将txt文件挪到对应平台的仿真文件夹下面即可。同时注意$readmemh用法的地址使用的是 /与window系统中的 \ 不一致。下面为代码举例reg [11:0]sine_hex[0:1023];//申明存储reg数组 reg [11:0]din; integer i; initial begin $readmemh(D:/FPGA_Pro/Test_CSDN/sinewave_hex.txt,sine_hex); //初始化数据到数组中 end initial begin for(i0;i1024;ii1)begin din sine_hex[i]; //赋值波形数据实际应用中向算法处理模块的输入端口赋值 #1; end for(i0;i1024;ii1)begin din sine_hex[i]; #1; end $stop; end下图为仿真的波形效果除此之外$readmemh用法还可以指定txt文件的数据存储在reg数组的具体地址位置。下面举一个例子首先申明一个12bit深度为4096的reg数组用来存放波形数据。第1组波形为1024点组成的正弦波数据数据位宽为12bit数据类型为16进制表示。第2组波形为1024点组成的三角波数据数据位宽为12bit数据类型为16进制表示。第3组波形为1024点组成的余弦波数据数据位宽为12bit数据类型为2进制表示。第4组波形为1024点组成的方波数据数据位宽为12bit数据类型为2进制表示。或者空格分隔表示代码如下在$readmemh和$readmemb中指定写入到reg数组的具体地址。reg [11:0]DDS[0:4095]; //申明波形reg数组DDS reg [11:0]din; integer i; initial begin $readmemh(D:/FPGA_Pro/Test_CSDN/sinewave_hex.txt,DDS,0,1023); //16进制读存储在DDS[0:1023] $readmemh(D:/FPGA_Pro/Test_CSDN/triwave_hex.txt,DDS,1024,2047);//16进制读存储在DDS[1024:2047] $readmemb(D:/FPGA_Pro/Test_CSDN/coswave_bin.txt,DDS,2048,3071);//2 进制读存储在DDS[2048:3071] $readmemb(D:/FPGA_Pro/Test_CSDN/sqwave_bin.txt,DDS,3072,4095); //2 进制读存储在DDS[3072:4095] end initial begin for(i0;i4096;ii1)begin din DDS[i]; //对波形数据进行赋值 #1; end $stop; end下图为仿真的波形效果以上的代码同样适用于modelsim平台下面是modelsim的效果1.2 $fgetc、$fgets和$fread使用按字符读取$fgetc、$fgets和$fread主要用于从文件中获取字符信息信息以ASCII码的形式存储。想要通过上述函数获取信息需要配合使用$fopen和$fclose函数。通过$fopen来获取文件句柄句柄一般通过integer类型存储。后续$fgetc等函数可以通过操作句柄对文件进行读写操作。1.2.1 $fgetc$fgetc ( fd )从句柄fd中获取一个字符返回值为8bit。$fgetc的功能是从文件中获取一个字符即8bit的char类型。在连续调用$fgetc时会在文件中依次获取下一个字符相当于读取指针在逐渐后移。同时可以使用$ungetc函数将字符进入读取缓冲区让下一次$fgetc的内容为缓冲区内容。下面进行代码举例。文件内容如下第一行的字符为0 空格 1 空格 2 空格 3 回车符示例代码如下integer fd1; //句柄 initial begin fd1 $fopen(D:/FPGA_Pro/Test_CSDN/s1.txt,r); //以可读的类型打开 end integer i; reg [7:0]c; //存储8bit的字符 initial begin for(i0;i28;ii1)begin c $fgetc ( fd1 ); //依次从文件中获取字符 $display(c%s, c%h,c,c); //打印字符按照字符和ascii的形式 end $fclose(fd1); //关闭句柄 end控制台的输出效果如下前面输出字符后面输出16进制的ascii码下面添加了$ungetc函数进行演示代码如下integer fd1; //句柄 integer code; //返回操作状态记录是否有错误发送 initial begin fd1 $fopen(D:/FPGA_Pro/Test_CSDN/s1.txt,r); //可读 end integer i; reg [7:0]c; reg [7:0]c1 ?; reg [7:0]c2 e; reg [7:0]c3 z; initial begin for(i0;i28;ii1)begin c $fgetc ( fd1 ); $display(c%s, c%h,c,c); end code $ungetc ( c,fd1 ); //将文件中最后一个字符$进入读取缓冲 c $fgetc ( fd1 ); //读取字符$ $display(c%s, c%h,c,c); code $ungetc ( c1,fd1 ); //将c1?进入读取缓冲 code $ungetc ( c2,fd1 ); //将c2e进入读取缓冲 code $ungetc ( c3,fd1 ); //将c3z进入读取缓冲 c $fgetc ( fd1 ); //读取字符z $display(c%s, c%h,c,c); c $fgetc ( fd1 ); //读取字符e $display(c%s, c%h,c,c); c $fgetc ( fd1 ); //读取字符? $display(c%s, c%h,c,c); $fclose(fd1); end控制台的输出效果为添加代码的输出效果在红色框内1.2.2 $fgets$fgets ( str , fd )从句柄fd中读取一行字符将字符写入str中返回值为操作状态。$fgets的功能是1次读取1行数据。但是需要注意为一行数据申明存储空间reg时需要考虑换行符多申明8bit否则出现次序的混乱。$fgets函数完成的条件是存储空间被写满或者在文件中读取到了换行符。下面进行代码演示。文件内容如下每一行有4个字符和一个换行符示例代码如下integer fd1; //句柄 integer code;//返回操作状态 initial begin fd1 $fopen(D:/FPGA_Pro/Test_CSDN/s1.txt,r); //可读 end integer i; reg [5*8-1:0]str; //每一行有5个字符所以需要5*840比特来存储一行数据 initial begin for(i0;i4;ii1)begin code $fgets ( str,fd1 ); //依次读取每一行的字符串并将字符串写入str中 $display(str%s, str%h,str,str); end $fclose(fd1); end效果展示1str的位宽为5*840bitstr里面正好存储5个字符且下一行读取正确下面修改str的位宽来演示效果。效果展示2str的位宽为4*832bitstr里面只能存储4个字符。由于在读取中没有读到换行符无法得知换行时刻下一行读取错误效果展示3str的位宽为7*832bitstr能够存储5个字符下一行读取正确。str没有被填满str的高位为全0即空格符1.2.3 $fread$fread ( mem , fd )从句柄fd中读取字符串存入mem中mem一般为reg数组返回值为操作状态。$fread的功能是读取整个文件的内容并将内容填入变量或者数组中。一般而言文件的内容排版需要工整规律保证内容在填入变量和数组的过程中没有问题。$fread函数完成的条件是数组被写满或者文件被读完。下面进行代码举例。文件内容如下每组字符长度一致字符分割方式相同即使用1个空格或者1个换行符代码如下integer fd1; //句柄 integer code; //返回状态 initial begin fd1 $fopen(D:/FPGA_Pro/Test_CSDN/s1.txt,r); //可读 end integer i; reg [6*8-1:0]file_data[0:7]; //reg数组用于存放文件内容存储字符数为6*848字符 initial begin code $fread(file_data,fd1); //将文件内容写入reg数组中直到reg数组写满或者文件读空 for(i0;i8;ii1)begin $display(file_data[%2d]%s,%h,i,file_data[i],file_data[i]); //显示reg数组的内容 end $fclose(fd1); end对应上文txt的两种分割方法第一种用空格分割第二中用换行符分割效果如下上述有关$fgetc$fgets$fread的用法都是按照字符串的方式进行读取并不是按照数据格式进行读取。1.3小节介绍按照数据格式读取的方式。1.3 $fscanf和$sscanf将字符处理成数据1.3.1 $fscanf$fscanf ( fd , format , args )从句柄fd中读取字符并按照format格式转换转换结果写入args中返回值为操作状态。$fscanf函数中format常用的包含%b%o%d%h等分别表示二进制八进制十进制和十六进制。$fscanf停止的条件是读取到了空格、制表符、换行符或换页符等。下面举一个例子。txt文件的内容为代码为integer fd1; //句柄 integer code; //返回操作状态 initial begin fd1 $fopen(D:/FPGA_Pro/Test_CSDN/s1.txt,r); //可读 end integer i; reg [19:0]din; //存放$fscanf读取的数据位宽与单个数据位宽一致 reg [19:0]file_data[0:7]; //将文件中的所有数据进行存储 initial begin for(i0;i8;ii1)begin code $fscanf(fd1,%h,din); //将16进制数据写入din中 file_data[i] din; //依次记录所有16进制数据 end for(i0;i8;ii1)begin $display(file_data[%2d]%h,i,file_data[i]); //输出数据进行查看 end $fclose(fd1); end控制台输出结果为如果din的位宽比20bit小的话例如din的位宽为8bit那么第一个数据20h01234会按照低位对齐即din8h34。如果din的位宽比20bit大的话例如din为28bit那么高位补零即din28h0001234。1.3.2 $sscanf$sscanf( str , format , args )将字符串str按照format格式转换忽略无法转换的字符例如空格换行符等转换结果写入args中返回值为操作状态。在之前$fread的基础上进行举例txt文件内容依旧如下代码如下integer fd1; //句柄 integer code; //返回操作状态 initial begin fd1 $fopen(D:/FPGA_Pro/Test_CSDN/s1.txt,r); //可读 end integer i; reg [6*8-1:0]file_data[0:7]; //存储字符串位宽48bit reg [19:0]tran_data[0:7]; //存储转换后的数据位宽20bit initial begin code $fread(file_data,fd1); //读取文件中的字符串存储到file_data中 for(i0;i8;ii1)begin $display(file_data[%2d]%h,i,file_data[i]); //显示file_data内容按照ascii码显示 end for(i0;i8;ii1)begin code $sscanf(file_data[i],%h,tran_data[i]); //将file_data中的字符转换成16进制数据存储到对应的tran_data中转化过程中忽略空格、换行符等 end for(i0;i8;ii1)begin $display(tran_data[%2d]%h,i,tran_data[i]); //显示转换后的16进制数据 end $fclose(fd1); end控制台输出结果为2、写入txt文件2.1 $writememh和$writememb用法$writememh和$writememb用法和$readmemh和$readmemb的用法相对应将reg数组中的数据保存到txt文件中去。同样可以按照16或2进制形式保存也可以指定保存的是reg数组的具体地址位置。实际使用时把算法模块的输出结果先存入reg数组中最后在写入txt文件中方便软件调取数据进行结果的比较。在1.1例子的基础上添加写入代码。将DDS数组的地址[0:2047]按照2进制的形式写入到文件ddswave_bin.txt中去。将DDS数组的地址[2048:4095]按照16进制的形式写入到文件ddswave_hex.txt中去。代码如下所示reg [11:0]DDS[0:4095]; reg [11:0]din; integer i; initial begin $readmemh(D:/FPGA_Pro/Test_CSDN/sinewave_hex.txt,DDS,0,1023); $readmemh(D:/FPGA_Pro/Test_CSDN/triwave_hex.txt,DDS,1024,2047); $readmemb(D:/FPGA_Pro/Test_CSDN/coswave_bin.txt,DDS,2048,3071); $readmemb(D:/FPGA_Pro/Test_CSDN/sqwave_bin.txt,DDS,3072,4095); end initial begin for(i0;i4096;ii1)begin din DDS[i]; #1; end $writememb(D:/FPGA_Pro/Test_CSDN/ddswave_bin.txt,DDS,0,2047); //按2进制将DDS[0:2047]写入ddswave_bin.txt $writememh(D:/FPGA_Pro/Test_CSDN/ddswave_hex.txt,DDS,2048,4095);//按16进制将DDS[2048:4095]写入ddswave_hex.txt $stop; end结果如下所示2.2 $fwrite$fwrite的功能是将数据按照一定的格式写入到txt文件中。注意这里文件打开是要以w格式打开即可写格式。在写完txt文件之后需要用$fclose(fd)关闭句柄否则在txt文件中可能看不到数据或者看到的数据不完整。在举例代码如下。integer fd2; //句柄 initial begin fd2 $fopen(D:/FPGA_Pro/Test_CSDN/s2.txt,w); //可写 end integer i; reg [11:0]r_data[0:1023]; //初始化待写入txt文件的数据 initial begin for(i0;i1024;ii1)begin r_data[i] i; //初始化数据 end for(i0;i1024;ii1)begin $fwrite(fd2,%d ,r_data[i]); //按照10进制的形式将数据写入txt文件 end $fclose(fd2); endtxt文件中结果为可以根据需求更改写入txt文件的数据格式例如将$fwrite(fd2,%d ,r_data[i]);修改为$fwrite(fd2,%h\n,r_data[i]);结果实现如下。$fwrite函数适合用于实时输出结果到txt文件中。例如根据模块的输出有效信号实时地将结果写入到txt文件中下面举例相关写法这里不给出结果。integer fd; initial fd $fopen(...../文件名,w); wire [...]out_valid; wire [...]dout; always(posedge clk) if(out_valid) //out_valid是输出有效信号 $fwrite(fd,%h\n,dout); //dout为模块输出结果 initial begin #......; //延时适当的时间后关闭句柄 $fclose(fd); end除了$fwrite函数之外还有函数$fwriteb、$fwriteh和$fwriteo等我觉得$fwrite已经够用了所以这里省略不在整理。以上就是对txt文件进行读写的一些方法总结希望对大家有帮助。有其他好用的方法欢迎在评论区进行补充。