Easy Tutorial
❮ Closure Intro These Pain Only Programmers Know ❯

7.2 Verilog File Operations

Category Advanced Verilog Tutorial

Verilog provides several system tasks for file operations. The commonly used system tasks include:

When using file operation tasks (especially $sformat, $gets, $sscanf, etc.), it is necessary to determine which system task to use based on the file nature and variable content, and ensure the consistency of parameters and variable types with the file content, avoiding confusion between string types and multi-binary types.

File Open/Close

System Task Call Format Task Description
File Open fd = $fopen("fname", mode); fname is the name of the file to be opened <br> fd is the returned 32-bit file descriptor <br> --- fd is non-zero when opened correctly <br> --- fd is zero when opening fails <br> mode specifies the file open mode
File Close $fclose(fd); Closes the file corresponding to fd
File Error err = $ferror(fd, str); When the file is opened normally: <br> --- both err and str are zero <br> When opening the file fails: <br> --- err returns a non-zero value indicating an error <br> --- str returns a non-zero value storing the error type <br> --- the official recommendation is for str to be 640-bit wide

Example code is as follows:

Example

//open/close file
   integer fd1, fd2;
   integer err1, err2;
   reg [320:0] str1, str2; // error type variables can also be supported string types
   initial begin
      //existing file
      fd1 = $fopen("./DATA_RD.HEX", "r");   // open existing file
      err1 = $ferror(fd1, str1);
      $display("File1 descriptor is: %h.", fd1); // non-zero value
      $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"); // file to be opened does not exist
      err2 = $ferror(fd2, str2);
      $display("File2 descriptor is: %h.", fd2); // 0
      $display("Error2 number is: %h.", err2);   // non-zero value
      $display("Error2 info is: %s.", str2);     // non-zero value
      $fclose(fd2);
   end

File open mode types and their descriptions are as follows:

r Open a text file for reading only.
w Open a text file for writing only. If the file exists, its content will be deleted. If the file does not exist, a new file will be created.
a Open a text file for appending data at the end. If the file does not exist, a new file will be created.
rb Open a binary file for reading only.
wb Open or create a binary file for writing only.
ab Open a binary file for appending data at the end.
r+ Open a text file for both reading and writing.
w+ Open or create a text file for both reading and writing. If the file exists, its content will be deleted. If the file does not exist, a new file will be created.
a+ Open a text file for both reading and writing. If the file does not exist, a new file will be created. Reading starts from the beginning of the file, but writing can only be in append mode.
rb+ Open a binary text file for both reading and writing, similar to "r+".
wb+ Open or create a binary text file for both reading and writing, similar to "w+".
ab+ Open a binary text file for both reading and writing, similar to "a+".

File Write

The system tasks for writing to a file mainly include: $fdisplay, $fwrite, $fstrobe, $fmonitor, and their corresponding formatted system tasks like $fdisplayb, $fdisplayh, $fdisplayo, etc.

Call Format Task Description
$fdisplay(fd, arguments); Write to file in order or conditionally, with automatic line break.
$fwrite(fd, arguments); Write to file in order or conditionally, without automatic line break.
$fstrobe(fd, arguments); Write to file after the statement execution completes.
$fmonitor(fd, arguments); Write to file whenever data changes.

Compared to the standard display tasks $display, $write, $strobe, $monitor, the file writing system tasks require specifying the file descriptor fd in addition to the usage format, and the rest of the printing conditions and timing characteristics are consistent with their corresponding display tasks.

An example of writing to a file using the append mode is as follows:

Example

//(2) write file
   integer fd;
   integer err, str;
   initial begin
      fd = $fopen("./DATA_RD.HEX", "a+");  // open in append mode at the end
      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); // last line does not break
      end
      $fclose(fd);
   end

Opening the file DATA_RD.HEX will show that 3 new lines of data have been added to the end of the file.

String Write

Verilog also provides system tasks for writing data into strings: $swrite and $sformat.

Call Format Task Description
$swrite(reg, list_of_arguments); Write string to variable reg in order or conditionally.
len = $sformat(reg, format_str, arguments); Write string to variable reg according to format format_str. <br> The format is consistent with the format specified for $display. <br> It is not recommended to omit the second parameter format_str. <br> Can return the string length len.

The second parameter format for $sformat is of string type, and it is generally recommended not to omit it. This parameter specifies the type of the input variable and can also include other string information. The types and usage can refer to the display function $display. This parameter can also be of register type, but it requires the stored data to be normal string data.

An example of writing to a string is as follows:

Example

//(3) write string
   reg [299:0] str_swrite, str_sformat;
   reg [63:0] str_buf;
   integer    len, age;
   initial begin
      #20;
      str_buf   = "tutorialpro!";
      age       = 9;

      //$swrite specifying format to write a string containing variables
      $swrite(str_swrite, "%s age is %d", str_buf, age);
      $display("%s", str_swrite);
      //$swrite directly writing a string without variables
      $swrite(str_swrite, "years ", "old.");
      $display("%s", str_swrite);
      //$swrite writing a string containing variables without specifying format, not recommended
      $swrite(str_swrite, age);
      $display("$swrite err test: %d", str_swrite);

      $display();
     //$sformat specifying format to write a string containing variables
      $sformat(str_sformat, "I have learnt in %s", str_buf);
      $display("%s", str_sformat);
      //$sformat directly writing a string without variables, and getting the string length
      len = $sformat(str_sformat, "for 4 years!");
      $display("%s", str_sformat);
      $display("$sformat len: %d", len);
      //$sformat directly writing multiple strings without variables at once, not recommended
      $sformat(str_sformat, "for", "4", "years!");
      $display("$sformat err test: %s", str_sformat);
   end

Ignoring the spaces in the print information, the debug output is as follows:

From this, it can be seen that the usage of $sformat and $swrite can be consistent, such as $sformat can use the specified format to write strings, or write a string without variables at once. In this case, $sformat is equivalent to not specifying the variable type in the second parameter, so the third parameter should be omitted.

$swrite can also write multiple strings without variables at once, while $sformat does not allow such calls.

It is also recommended that when using $swrite to write strings containing variables, specify the variable type, otherwise the results may be unpredictable.

File Read

System Task Call Format and Description
Read file by character c = $fgetc(fd);
Output data from fd to variable c in character format, c width should be at least 8 <br> When reading fails, c value is EOF(-1), and $ferror can be used to check the error type
Write buffer by character code = $ungetc(c, fd);
Write character c to the buffer of file fd <br> The value of c will be returned when $fgetc is called next time, and the content of file fd itself will not change <br> The return value code is 0 when writing to the buffer normally, and EOF when an error occurs
Read file by line code = $fgets(str, fd)

Read characters consecutively until the variable str is filled, or the line is finished, or the end of the file is reached. The return value code is the number of lines (times) read during normal operation, and code is 0 when an error occurs.

Task Format Description
Read file by format code = $fscanf(fd, format, args); Read data from file fd into variable args according to format format. Refer to $display for format specifications. The stop condition for a single read is a space or newline. The return value code is 0 when an error occurs.
Read string by format code = $sscanf(str, format, args); Read string variable str into variable args according to format format. The calling format is consistent with $fscanf.
Read file in binary code = $fread(store, fd, start, count); Read data from file fd into array or register variable store in binary stream format. start is the starting address in the file, and count is the length to read. If start/count are not specified, the data will fill the variable store entirely. If store is a register type, the start/count parameters are invalid, and reading stops after one fill of the store variable.
c0dec0de
5555aaaa
12345678
aaaa5555
New data1: 80000003
New data2: 00000000
New data3: 00000000

Example of $fgetc, $ungetc calls

Example

//(4.1) read char
   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&lt;13; i++) begin
            char_buf[7:0] = $fgetc(fd) ;  //Read single character
            $write("%c", char_buf[7:0]) ; //Print each character without newline
         end
         $write(".\n") ;
      end

      $ungetc("1", fd) ;          //Write to file buffer 3 times consecutively
      $ungetc("2", fd) ;
      $ungetc("3", fd) ;
      char_buf[7:0]   = $fgetc(fd) ;  //Read 3
      char_buf[15:8]  = $fgetc(fd) ;  //Read 2
      char_buf[23:16] = $fgetc(fd) ;  //Read 1, end of buffer
      char_buf[31:24] = $fgetc(fd) ;  //Read a
      $display("Read char after $ungetc: %s", char_buf);
      $fclose(fd);
   end

Simulation results are as follows.

As shown in the figure, the 13 characters read by $fgetc are correct, including the newline character.

After writing character data to the file buffer with $ungetc, $fgetc can read the character data from the file buffer. The read and write operations follow the First In Last Out (FILO) principle, similar to a stack. When characters "123" are written first, the read data is "321".

After the file buffer is read completely, the subsequent character data read still follows the position of the previous file read, i.e., the character "a" in "a123" in the log.

During this process, the content of the file DATA_RD.HEX remains unchanged.

Example of $fgets calls

Example

//(4.2) read line
   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&lt;6; i++) begin  //Read line by line in string format
            code = $fgets(line_buf[i], fd) ;  //Ends with "\n", will print 2 lines
            $display("Get line data%d: %s", i, line_buf[i]) ;
         end
      end
      //Display in hexadecimal, showing corresponding ASCII codes
      $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

Simulation results are as follows.

The first 4 lines of data are read and displayed as strings, and the results are normal.

When reading the 5th line of data, due to the 100-bit width limitation of the variable line_buf, the file content "New data1: 80000003 " needs to be read in 2 parts.

Because each line ends with a newline character "\n", using the $display function to print will result in an extra blank line.

When reading as a string and displaying the data in hexadecimal, the corresponding data content of the file cannot be directly displayed intuitively. For example, the second line does not display "12345678," but its corresponding ASCII code. Therefore, $fgets reads in string format, which needs to be noted.

Example of $fscanf, $sscanf calls

Example

//(4.3) $fscanf/$sscanf
   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
      #32 ;
      fd = $fopen("DATA_RD.HEX", "r");
      err = $ferror(fd, str);
      if (!err) begin
         for (i=0; i&lt;4; i++) begin
            //The first 4 lines of data are read and displayed in hexadecimal
            code = $fscanf(fd, "%h", data_buf[i]);
            $display("$fscanf read data%d: %h", i, data_buf[i]) ;
         end
         for (i=4; i&lt;6; i++) begin
            //The last 2 lines of data are read and displayed as strings
            code = $fscanf(fd, "%s", string_buf[i]);
            $display("$fscanf read data%d: %s", i, string_buf[i]) ;
         end
      end

      //(1) $sscanf source variable data_test is a string type
      data_test = "fedcba98" ;
      code = $sscanf(data_test, "%h", data_get);
      $display("$sscanf read data0: %h", data_get) ;
      //(2) $sscanf: Convert the source variable data_test to a string variable first
      code = $sformat(data_test, "%h", data_buf[2]);
      code = $sscanf(data_test, "%h", data_get);
      //Directly inputting a hexadecimal variable is not recommended
      //code = $sscanf(data_buf[2], "%h", data_get); 
      $display("$sscanf read data0: %h", data_get) ;
      $fclose(fd) ;
   end

Simulation results are as follows.

Using $fscanf to read and display the first 4 lines of the file in hexadecimal and the last 2 lines as strings, both are normal.

When using $sscanf to move the content of the source register to the destination register, the content in the source register should be string data.

For example, when using $sscanf to move the hexadecimal data data_buf[2] to the register variable data_get, you can first use the string writing task $sformat to convert the content of the source variable data_buf[2] to a string type and store it in the variable data_test. Then use $sscanf to move the content of data_test to the variable data_get in hexadecimal. Printing the variable data_get in hexadecimal format will display correctly.

If you directly use $sscanf to move the hexadecimal formatted data data_buf[2] directly to the variable data_get, the content in data_get will be abnormal.

By the way, registers can be assigned directly to each other!

Example of $fread calls

Example

//(4.4) $fread
   reg [71:0]   bin_buf [3:0] ; //Each line has 8 word data and 1 newline character
   reg [143:0]  bin_reg ;
   initial begin
      #40 ;
      fd = $fopen("DATA_RD.HEX", "r");
      err = $ferror(fd, str);
      if (!err) begin
         code = $fread(bin_buf, fd, 0, 4); //Array type read, read 4 times
         $display("$fread read data %h", bin_buf[0]) ;//Display in hexadecimal
         $display("$fread read data %h", bin_buf[1]) ;
         $display("$fread read data %s", bin_buf[2]) ;//Display as string
         $display("$fread read data %s", bin_buf[3]) ;
      end

      fd = $fopen("DATA_RD.HEX", "r");
      code = $fread(bin_reg, fd); //Single register read
      $display("$fread read data %h", bin_reg) ;
      $fclose(fd) ;
   end

Simulation results are as follows.

When $fread reads the file in binary, the starting address and read length are parameters set for array-type variables.

If the variable type for storing data is a non-array register type, it will only perform a single read until the register variable is filled. This is a Chinese to English translation. Please provide the English translation for this text. Do not provide any explanations or text apart from the translation.

Chinese: | --- | --- | --- | | 获取文件位置 | pos = $ftell( fd ) ; | Returns the current position of the file pointer relative to the beginning of the file, with the initial address being 0. <br> The offset is measured in bytes (8 bits). <br> Used in conjunction with $fseek. | | 重定位 | code = $fseek(fd, offset, type) ; | Sets the position for the next input or output operation. <br> offset is the specified offset. <br> type is the operation type for the offset. <br> --- 0: Sets the position to the offset address. <br> --- 1: Sets the position to the current position plus the offset. <br> --- 2: Sets the position to the end of the file plus the offset, often using a negative number to indicate an offset from the end of the file. | | 无偏移重定位 | code = $rewind( fd ) ; | Equivalent to $fseek( fd, 0, 0) ; | | 判断文件尾部 | code = $feof(fd) ; | Determines if the end of the file has been reached. <br> Returns 1 if the end of the file is detected, otherwise returns 0. |

The content of the file DATA_RD.HEX can be represented as follows.

The newline character "\n" serves as the end-of-line marker, so the file size is: 4x9 + 3x20 = 96 bytes.

File positioning test code is as follows:

Example

// file position
   reg [31:0]   data4 ;      // Register variable length is 4 bytes
   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); // Starts reading from position 0
         pos  = $ftell(fd);      // Position is 8 after reading 8 bytes, coordinates (0,8)
         $display("Position after read: %d", pos) ;
         $display("1st read data: %h", data4) ;

         // type = 0
         code = $fseek(fd, 4, 0) ; // Starts reading from position 4, coordinates (0,4)
         code = $fscanf(fd, "%h", data4); // Stops reading at the newline character
         pos  = $ftell(fd);      // Position is 8 after reading 4 bytes, coordinates (0,8)
         $display("type 0: current position: %d", pos) ;
         $display("type 0: read data: %h", data4) ;
         // type = 1
         code = $fseek(fd, 4, 1) ; // Starts reading from position 4+9=12, coordinates (1,3)
         code = $fscanf(fd, "%h", data4); // Stops reading at the newline character
         pos  = $ftell(fd);      // Position is 17 after reading 5 bytes, coordinates (1,8)
         $display("type 1: current position: %d", pos) ;
         $display("type 1: read data: %h", data4) ;
         // type = 2
         code = $fseek(fd, -(96-31), 2) ; // Starts reading from position 31, coordinates (3,4)
         code = $fscanf(fd, "%h", data4); 
         pos  = $ftell(fd);      // Position is 35 after reading 4 bytes, coordinates (3,8)
         $display("type 2: current position: %d", pos) ;
         $display("type 2: read data: %h", data4) ;

         // rewind read
         code   = $rewind(fd) ; // Resets the file pointer to the beginning of the file
         pos    = $ftell(fd);  // Position is now 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

Simulation results are as follows.

From the log, it can be seen that an extra line of data was printed at the end, which is due to an empty line at the end of the file DATA_RD.TXT (result of a newline operation), and the system task $feof does not consider this empty line as the end of the file, so it still returns 0. However, since there is no data in this line, the data read is unpredictable.

To eliminate the influence of the newline character at the end of the last line of data in the file, the last file writing system task $fdisplay in the "file writing" example can be replaced with $write.

The rest of the log, combined with the code comments, shows that the simulation is correct, and no further explanation is provided here.

Loading Memory

System Task Call Format and Description
Load Hexadecimal File $readmemh("fname", mem, start_addr, finish_addr)
fname is the data file name. <br> mem is an array/memory variable. <br> start_addr and finish_addr are the start and end addresses, respectively. <br> start_addr and finish_addr can be omitted, in which case the loading stops when the memory variable mem is filled or the file is fully read. <br> The file content should only include whitespace characters (or newline, space characters), binary or hexadecimal data. <br> Comments are marked with "//", and data is recommended to be separated by newline characters.
Load Binary File $readmemb("fname", mem, start_addr, finish_addr)
Usage format is the same as $readmemb.

The content of the file DATA_WITHNOTE.HEX is as follows, and the content of this file is loaded into the memory variable.

Example code is as follows:

Example

// 6 load mem
   reg [31:0]   mem_load [3:0] ;
   initial begin
      #50 ;
      $readmemh("./DATA_WITHNOTE.HEX", mem_load);
      $display("Read memory1: %h", mem_load[0]) ;
      $display("Read memory2: %h", mem_load[1]) ;
      $display("Read memory3: %h", mem_load[2]) ;
      $display("Read memory4: %h", mem_load[3]) ;
   end

Simulation results are as follows:

Source Code Download for This Chapter

Download

-0.1 Digital Logic Design

-0.2 Verilog Coding Style

-0.3 Verilog Code Guide

-1.1 Verilog Gate Types

-1.2 Verilog Switch-Level Modeling

-1.3 Verilog Gate Delay

-2.1 Verilog UDP Basics

-2.2 Verilog Combinational Logic UDP

-2.3 Verilog Sequential Logic UDP

-3.1 Verilog Delay Models

-3.2 Verilog specify Block Statements

-3.3 Verilog Setup and Hold Time

-3.4 Verilog Timing Checks

-3.5 Verilog Delay Backannotation

-4.1 Verilog Synchronous and Asynchronous

-4.2 Verilog Clock Domain Crossing: Slow to Fast

-4.3 Verilog Clock Domain Crossing: Fast to Slow

-4.4 Verilog FIFO Design

-5.1 Verilog Reset Introduction

-5.2 Verilog Clock Introduction

-5.3 Verilog Clock Division

-5.4 Verilog Clock Switching

-6.1 Verilog Low Power Introduction

-6.2 Verilog System-Level Low Power Design

-6.3 Verilog RTL-Level Low Power Design (Part 1)

-6.4 Verilog RTL-Level Low Power Design (Part 2)

-7.1 Verilog Display Tasks

-7.3 Verilog Random Numbers and Probability Distribution

-7.4 Verilog Real to Integer Conversion

-7.5 Verilog Other System Tasks

-8.1 Verilog PLI Introduction

-8.2 Verilog TF Subroutines

-8.3 Verilog TF Subroutine List

-8.4 Verilog ACC Subroutines

-8.5 Verilog ACC Subroutine List

Follow on WeChat

❮ Closure Intro These Pain Only Programmers Know ❯