Search code examples
file-iovhdl

How to read elements from a line in VHDL?


I'm trying to use VHDL to read from a file that can have different formats. I know you're supposed to use the following two lines of code to read a line at a time, the read individual elements in that line.

readline(file, aline);
read(aline, element);

However my question is what will read(aline, element) return into element? What will it return if the line is empty? What will it return if I've used it let's say 5 times and my line only has 4 characters?

The reason I want to know is that if I am reading a file with an arbitrary number of spaces between valid data, how do I parse this valid data?

The file contains ASCII characters separated by arbitrary amounts of white space (any number of spaces, tabs, or new lines). If the line starts with a # that line is a comment and should be ignored.

Outside of these comments, the first part of the file contains characters that are only letters or numbers in combinations of variable size. In other words this:

123           ABC   12ABB3 

However, the majority of the file (after a certain number of read words) will be purely numbers of arbitrary length, separated by an arbitrary amount of white space. In other words, the second part of the file is this:

255 0       2245   625         430
2222  33        111111

and I must be able to parse these numbers (and interpret them as such) individually.


Solution

  • As mentioned in the comments, all the read procedures in std.textio and ieee.std_logic_textio skip over leading spaces apart from the character and string versions (because a space is as much a character as any other).

    You can test whether a line variable (the buffer) is empty like this:

    if L'length > 0 then
    

    where L is your line variable. There is also a set of overloaded read procedures with an extra status output:

    procedure read (L    : inout LINE;
                    VALUE: out   <type> ;
                    GOOD : out   BOOLEAN);
    

    The extra output - GOOD - is true if the read was successful and false if it wasn't. The advantage of these if that the read is unsuccessful, the simulation does not stop (as it does with the regular procedures). Also, with the versions in std.textio, if the read is unsuccessful, the read is non-destructive (ie whatever you were trying to read remains in the buffer). This is not the case with the versions in ieee.std_logic_textio, however.

    If you really do not know what format you are trying to read, you could read the entire line into a string, like this:

    variable S : string(1 to <some big number>);
    ...
    readline(F, L);
    assert L'length < S'length;  -- make sure S is big enough
    S := (others => ' '); -- make sure that the previous line is overwritten
    if L'length > 0 then
      read(L, S(1 to L'length);
    end if;
    

    The line L is now in the string S. You can then write some code to parse it. You may find the type attribute 'value useful. This converts a string to some type, eg

    variable I : integer;
    ...
    I := integer'value(S(12 to 14));
    

    would set integer I to the value contained in elements 12 to 14 of string S.

    Another approach, as suggested by user1155120 below, is to peek at the values in the buffer, eg

    if L'length > 0 then  -- check that the L isn't empty, otherwise the next line blows up
      if L.all(1) = '#' then
        -- the first character of the line is a '#' so the line must be a comment