SystemVerilog $feof()

Please help me :

int switch[string], min_address, max_address;
initial begin
int i, r, file;
string s;
file=$fopen(“switch.txt”, “r”);
$display(file);
while(! $feof(file)) begin
r = $fscanf(file, “%d %s”, i, s);
switch[s] = i;
end

 min_address = switch["min_address"];
 if(switch.exists("max_address"))
   max_address = switch["max_address"];
 else
    max_address = 1000;
  
  foreach(switch[s])
    $display("switch['%s'] = %0d", s, switch[s]);

end

ModelSim stops $feof()…

Thanks
Neddy

Neddy,

It would help us help you if you could explain what you mean by “stops”

Are you getting an error message? if so what is it?

Is the while loop ending to soon?

In reply to dave_59:

no error message
while loop without stop

In reply to Neddy:

That is still not enough information to us to help you. Please put in the effort as descriptive as possible.

You say the while loop does not stop. How do you know this? what have you tried to do to see what is happening inside the loop, like added extra $display statements.

try this
integer end;
while (end==0) begin
end= $feof(file);
end

I hit the same problem today, and after spending some time, I found that it’s due to wrong format specifiers in $fscanf.

r = $fscanf(file, “%d %s”, i, s);

SV expects a decimal and a string in the file, but it must have found something else.
If you assert this statement, you’ll find that the simulation will crash.

In reply to Neddy:

Your code does not have any error condition to handle bad/unexpected data in the input file

1800-2012 Sec 21.3.4.3 says this

If conversion terminates on a conflicting input character, the offending input character is left unread in the
input stream. Trailing white space (including newline characters) is left unread unless matched by a
directive. The success of literal matches and suppressed assignments is not directly determinable.

So when your line

r = $fscanf(file, "%d %s", i, s);

is executed, if the input file does not contain something that can be read in as %d followed by something that can be read in as an %s, then

the offending input character is left unread in the input stream

Therefore since you still have unread data in the input file, you are not at $feof so the while loop just iterates another time, and again just tries to read in the same thing it just failed on, and just continues to loop like this.

If you cannot guarantee that the input file will always have exactly the data you expect, you should add an error condition to your $fscanf code, to handle the situation of $fscanf reading something unexpected

Content of data_file:
08802000 ee69_0a75_3403_a586_cbcf_9dea_5cae_9e60
8802010 4c96_921f_6724_2263_fef5_c45c_7608_8499
8802020 8b02_143a_f6a8_1cea_33b5_5542_67fb_b654
8802030 973b_b697_7a39_f23c_3028_7282_2af2_92b8
8802040 9258_6c5b_7637_972a_5ec6_569c_addb_9051

    file = $fopen("data_file.txt","r");
      while (!$feof(file)) begin
          c = $fscanf(file,"%h %h",addr,data);
	  $display("addr:%h <<< -- >>> data:%h",addr,data);
      end

Output :
addr:08802000 <<< – >>> data:ee690a753403a586cbcf9dea5cae9e60
addr:08802010 <<< – >>> data:4c96921f67242263fef5c45c76088499
addr:08802020 <<< – >>> data:8b02143af6a81cea33b5554267fbb654
addr:08802030 <<< – >>> data:973bb6977a39f23c302872822af292b8
addr:08802040 <<< – >>> data:92586c5b7637972a5ec6569caddb9051
addr:08802040 <<< – >>> data:92586c5b7637972a5ec6569caddb9051

Last dat getting twice… Can anyone please explain me why last data is getting twice here.

Thanks,
Mukesh

In reply to mukeshkumar.saha@reliabletechsys.com:
It’s because after the read of the last data value in the file, there are still more characters in the file (like a newline) and the final call to
$fscanf
fails and leaves
addr
and
data
unmodified. What you need to do is check the return value of
$fscanf
.

file = $fopen("data_file.txt","r");
while ($fscanf(file,"%h %h",addr,data)==2) begin
    $display("addr:%h <<< -- >>> data:%h",addr,data);
      end

In reply to Neddy:

Hi this is a description on how to read from binary files. It has some examples on how to use EOF. I hope it helps.

Below the example for reading from a binary file with systemverilog.

As shown in IEEE SV Standard documentation, the “nchar_code” will return the number of bytes/chars read. In case EOF have been already reached on last read this number will be zero.
Please, notice that “nchar_code” can be zero but EOF has not been reached, this happens if you have spaces or returns at the end of the data file.

You can control the number of bytes to be read with the $fread function call (“nchar_code”). This is done with the type definition of the “data_write_temp”. If the “data_write_temp” variable is 16bits long then it will read 16bits each time the $fread is called. In case, “data_write_temp” is 32bits as in the example, the $fread will read nchar_code=4bytes(32bits). You can also define an array and the $fread function will try to fill that array.

Lets define a multidimensional array mem.

     logic [31:0] mem [0:2][0:4][5:8];

In the example word contents, wzyx,

    -w shows the start of the word
    -z corresponds to words of the [0:2] dimension (3 blocks).
    -y corresponds to words of the [0:4] dimension (5 rows).
    -x corresponds to words of the [5:8] dimension (4 columns).

The file will be structure as below (notice @z shows the z dimension blocks):

    @0 w005 w006 w007 w008
       w015 w016 w017 w018
       w025 w026 w027 w028
       w035 w036 w037 w038
       w045 w046 w047 w048
    @1 w105 w106 w107 w108
       w115 w116 w117 w118
       w125 w126 w127 w128
       w135 w136 w137 w138
       w145 w146 w147 w148
    @2 w205 w206 w207 w208
       w215 w216 w217 w218
       w225 w226 w227 w228
       w235 w236 w237 w238
       w245 w246 w247 w248

In the previous structure, the numbers shows the index of each dimension.
e.g. w048 means, the word w (32bits) value on index z =0, index y= 4 and index x= 8.

Now, you have many ways to read this.
You can read all in a single shot using the type “mem” declared above, or you can do a while loop until EOF reading pieces of 32bits using a “data_write_temp” variable of 32bits. The loop is interesting if you want to do something some checks for every word piece and you are not interested having a memory value.

In case multidimensional array / single shot read is chosen, then you can either use $fread or use an specific function $readmemh defined in SV standard.

$readmemh("mem.data", mem, 1, (3*5*4));

is equivalent to

$readmemh("mem.data", mem);

The $readmemh spare you the need to open/close the file.

If you use $fread for one shot read


      logic [31:0]          mem [0:2][0:4][5:8];
      register_init_id      = $fopen("mem.data","rb");                 
      nchar_code = $fread(mem, register_init_id);   
      if (nchar_code!=(3*5*4)*4)) begin 
      `uvm_error("do_read_file", $sformatf("Was not possible to read the whole expected bytes")); 
      end    
      $fclose(register_init_id);

In case you wanted to do a loop using 32b word read. Then see the following example.

The example uses the data which is read from the file to write to AHB Bus using an AHB Verification Component.


        logic [31:0] data_write_temp;
        ...
        //DO REGISTER FILE
        register_init_id      = $fopen("../../software/binary.bin","rb");
        if (register_init_id==0) begin `uvm_error("do_read_file", $sformatf("Was not possible to open the register_init_id file")); end 
        count_32b_words=0;
        while(!$feof(register_init_id)) begin            
            nchar_code = $fread(data_write_temp, register_init_id);
            if ((nchar_code!=4)||(nchar_code==0)) begin
                if (nchar_code!=0) begin
                    `uvm_error("do_read_file", $sformatf("Was not possible to read from file a whole 4bytes word:%0d",nchar_code));
                end
            end else begin
                tmp_ahb_address = (pnio_pkg::conf_ahb_register_init_file_part1 + 4*count_32b_words);        
                data_write_temp = (data_write_temp << 8*( (tmp_ahb_address)%(DATAWIDTH/(8))));//bit shift if necessary not aligned to 4 bytes        
                `uvm_create_on(m_ahb_xfer,p_sequencer.ahb0_seqr);                         
                assert(m_ahb_xfer.randomize(* solvefaildebug *) with {                                       
                        write  == 1;//perform a write
                        HADDR  == tmp_ahb_address;
                        HSIZE  == SIZE_32_BIT;
                        HBURST == HBURST_SINGLE;
                        HXDATA.size() == 1; //only one data for single bust
                        HXDATA[0]  == data_write_temp;
                    }) else $fatal (0, "Randomization failed");                //end assert   
                `uvm_send(m_ahb_xfer);                  
                count_32b_words++;
            end //end if there is a word read
        end //end while    
        $fclose(register_init_id);

In reply to dave_59:

Hello Team,

I would like to know about,
how to skip the line of a file using file operations.
i.e by using $fgets(line,fd), we can get the lines of a file by putting in a while loop.

But my question is, if that line is empty I want next line. How to get the next line ???
I tried to put $fgets(line,fd) again and again, but it is not looking fine.

(I don’t want to use continue statement in while loop. I am comparing two files in a single while loop.)

Please help me out.

Thanks.

In reply to cdpvinjamuri:

Have you checked the return value of $fgets?

You need to provide some code and explain what you mean by “not looking fine”

In reply to dave_59:

Hi Dave,
Thanks for reply, please find the below snippet.

file1:
FF: A1 B1
FE: A2 B2
FD: A3 B3
FC: A4 B4

file2:
EF: A1 B1
EE: A2 B2
empty line…
EC: A3 B3

I want to compare 1st line of file1 with 1st line of file2, similarly 3rd line of file1 has to be compared with 4th line of file2 by skipping empty line(3rd line of file2).


task compare_files(input string ip_file,op_file);

    fd1 = $fopen(ip_file,"r");
    fd2 = $fopen(op_file,"r");
    fd3 = $fopen("cmp.out","w");

     while ($fgets(file1,fd1) && ($fgets(file2,fd2)) && (!$feof(fd1)) && (!$feof(fd2))) begin

	if($sscanf(file1,"%x: %x %x",addr1,data1,data2)==3)begin
	 data_final1 = {data1,data2};
	end

	
	if($sscanf(file2,"%x: %x %x",addr1,data1,data2)==3)begin
	data_final2 = {data1,data2};
	end

	//here I want to skip to the next line, if scanned line of fd2 is empty.
	//How to get the next line of fd2 ??
	//Aim is to compare the data_final1 and data_final2.

	//I achieved the aim by using associative array. 
	//But I want to know how to get next line without using continue statement in while loop.

	end

endtask:compare_files

In reply to cdpvinjamuri:

Maybe a good idea is to read the IEEE SV standard on section 21.3.5 File positioning
There you can find, the functions you need.
e.g.
$ftell is used to determine the current read or write position within a file. For example:
integer pos ;
pos = $ftell ( fd );
returns in pos the offset from the beginning of the file of the current byte of the file fd,

AND

integer code ;
code = $fseek ( fd, offset, operation );
code = $rewind ( fd );
$fseek and $rewind can be used to change the current read or write position within a file.
Offset is the number of bytes the file pointer will be moved taking as start point the operation point.
The “operation” point means:
0=from Beginning of file
1=from Current position
2=from End of file

In your case, you just need to move the file pointer from the current position of the file(operation=1) n bytes (where n is the number of bytes in one line)

I hope it helps

In reply to dave_59:

Hi Dave,
How would you handle the case of not reading the last line twice in the below case:
I have to start reading a file and compare it to the DUT output only when valid from DUT is high.

My initial code:

while ($feod(fd)) begin
  if (vif.valid ===1) begin
    $fscanf(fd, "%1b", vec_output);
    //Some comparison code
   end
end

The problem with the above code is I am reading the last line twice.

But if I follow what you mentioned above, the purpose of not comparing the data while valid=0 will not be met.

Thanks in advance.
Subhash

In reply to Subhash.Sangam:

while ($fscanf(fd, "%1b", vec_output) == 1) // while there is data to read
  begin
    @(posedge vif.clock iff vif.valid) // wait for valid DUT data
    //Some comparison code
  end

In reply to dave_59:

Thanks Dave. It works.

Hi people,
I want to activate something 3 lines before the end of the text file being read, how can I do that ?
Basically how can I identify ‘x’ lines before the end of the file ?

Thanks in advance!

In reply to Saraswati:

You should be asking new questions rather than replying to old questions unless you have a specific thing to add or need clarification. It helps other people when searching for answers to their questions.

You can’t know when you are 3 lines before the end of a file unless you read the whole file first into an array of string for each line, or you know the total size of a file and each line is a fixed length.