Search code examples
imagefilevhdlfpga

VHDL textio, reading image from file


I am trying to learn how to implement image processing algorithms in an FPGA and to do this I am working with a txt file that contains a bmp image (converted using MATLAB).

I am havin problems using the textio package, so by now I am only able to read the first column of data (but not the entire row of data).

The txt file have this aspect:

    1,1,0,0,0
    0,1,1,1,1
    1,0,0,0,0
    0,0,1,1,0
    1,1,1,1,1

a 5x5 matrix separated by commas. The output of the entity I have now in my simulations is

    1 0 1 0 1 

that corresponds to the first column. I don't understand why the code doesn't read all the line and when it ends jump to the next line.

Here is the process for read the file (I have add a variable named comma so I could detect the comma and skip it but still doesn't work ):

reading : process 

    constant filename : string := "C:\DOCUMENTACION\PROYECTOS\Envio_salida_VGA_atraves_FPGA\MatLab\Procesado de imagen con Toolbox\prueba.txt";
    file f : text open read_mode is filename;
    variable L : line;
    variable data_read : integer;
    variable comma : character;
begin
    while not endfile(f) loop
        wait until rising_edge(clk); 
            readline(f, L);
            read(L, data_read);

            while L = ',' loop
                read(L, comma);
            end loop;

            d_out <= data_read;
    end loop;

what is wrong with my code?


Solution

  • I don't understand why the code doesn't read all the line and when it ends jump to the next line.

    You're only trying to read one integer then one comma before the next readline.

    Also note as long as you can count on one character separating consecutive integers on a line you don't have to care what the character is (and you don't so much as look at comma).

    To read every integer on a line you need to pay attention to whether your read calls have consumed all the line buffer.

    I modified your code to demonstrate after saving your example data to a file named prueba.txt:

    library ieee;
    use ieee.std_logic_1164.all;
    use std.textio.all;
    
    entity prueba is
    end entity;
    
    architecture foo of prueba is
        signal d_out:   integer;
        signal clk:     std_logic := '0';
    begin
    reading:
        process
            constant filename:  string := "prueba.txt";
            file f:              text open read_mode is filename;
            variable L:          line;
            variable data_read:  integer;
            variable char:      character;  
            variable len:       integer;  
        begin
            while not endfile(f) loop
                readline(f, L);
    
                len := L'length;
                while len > 0 loop
                    read (L, data_read);
                    len := L'length;
                    if len > 0 then
                        read (L, char);
                        len := L'length;
                    end if;
                    wait until rising_edge(clk); 
                    d_out <= data_read;
                    report "data_read = " & integer'image(data_read);
                end loop;
            end loop;
            wait until rising_edge(clk);
            wait;                   
        end process;
    CLOCK:
        process
        begin
            wait for 5 ns;
            clk <= not clk;
            if Now > 250 ns then -- picked by prueba.txt number of elements
                wait;
            end if;
        end process;
    
    end architecture;
    

    Because a resulting waveform requires you count clocks or time instead of datums I added a report statement which gives:

    prueba.vhdl:33:17:@5ns:(report note): data_read = 1
    prueba.vhdl:33:17:@15ns:(report note): data_read = 1
    prueba.vhdl:33:17:@25ns:(report note): data_read = 0
    prueba.vhdl:33:17:@35ns:(report note): data_read = 0
    prueba.vhdl:33:17:@45ns:(report note): data_read = 0
    prueba.vhdl:33:17:@55ns:(report note): data_read = 0
    prueba.vhdl:33:17:@65ns:(report note): data_read = 1
    prueba.vhdl:33:17:@75ns:(report note): data_read = 1
    prueba.vhdl:33:17:@85ns:(report note): data_read = 1
    prueba.vhdl:33:17:@95ns:(report note): data_read = 1
    prueba.vhdl:33:17:@105ns:(report note): data_read = 1
    prueba.vhdl:33:17:@115ns:(report note): data_read = 0
    prueba.vhdl:33:17:@125ns:(report note): data_read = 0
    prueba.vhdl:33:17:@135ns:(report note): data_read = 0
    prueba.vhdl:33:17:@145ns:(report note): data_read = 0
    prueba.vhdl:33:17:@155ns:(report note): data_read = 0
    prueba.vhdl:33:17:@165ns:(report note): data_read = 0
    prueba.vhdl:33:17:@175ns:(report note): data_read = 1
    prueba.vhdl:33:17:@185ns:(report note): data_read = 1
    prueba.vhdl:33:17:@195ns:(report note): data_read = 0
    prueba.vhdl:33:17:@205ns:(report note): data_read = 1
    prueba.vhdl:33:17:@215ns:(report note): data_read = 1
    prueba.vhdl:33:17:@225ns:(report note): data_read = 1
    prueba.vhdl:33:17:@235ns:(report note): data_read = 1
    prueba.vhdl:33:17:@245ns:(report note): data_read = 1

    Where we find all the integers in prueba.txt are read.

    Note I added a variable named len to hold the number of characters available in L. Every read or every readline len gets updated. If there are no more characters on the line we don't try to read.

    The evaluation of Now in the CLOCK process and the extra wait until rising_edge(clk); and following wait in the reading process are just to stop the simulation where a waveform would be useful.


    We use L'length to tell us if there are any more datums on a line or whether we should fall out into the outer while loop and call readline if not at the end of the file.

    You could also note the process can be re-written using only the 'length attribute:

    reading:
        process
            constant filename:  string := "prueba.txt";
            file f:              text open read_mode is filename;
            variable L:          line;
            variable data_read:  integer;
            variable char:      character;  
        begin
            while not endfile(f) loop
                readline(f, L);
                while L'length > 0 loop
                    read (L, data_read);
                    if L'length > 0 then
                        read (L, char);
                    end if;
                    wait until rising_edge(clk); 
                    d_out <= data_read;
                    report "data_read = " & integer'image(data_read);
                end loop;
            end loop;
            wait until rising_edge(clk);
            wait;                   
        end process;
    

    And this gives the same answer. We'd use a len variable if we were to do something clever like throw away comments, which would also require we scan L and trim trailing white space. We can assign values to len but not L'length. Because there is nothing trailing the last datum in your prueba.txt we can simply use the length attribute.