Search code examples
vhdl

Reading a matrix from file


I am trying to read a matrix from a file, it contains the colors of the pixels of a gray scale image. After this I will have to put the data I read into a register and perform some operations on it. When I am trying to simulate my code, the data is read alright in the "data" signal, but when I try to store an element, I read in the "test" signal to show it in the "last_elem" output it shows -2147483648. What am I doing wrong and why can't I access the data I read?

entity Main is
Port(
rstb:in std_logic;
clk:in std_logic;
row:out integer;
col:out integer;
last_elem:out integer
);
end Main;

architecture Behavioral of Main is
type matrixData is array(0 to 240, 0 to 217) of integer;
signal data:matrixData;
signal test:integer;

begin
    process(clk)
    file read_file:text;
    VARIABLE file_line:LINE;
    VARIABLE row_counter:INTEGER:=0;
    variable rows:integer;
    variable cols:integer;
    variable read_value:integer;
    begin


    file_open(read_file, "D:\Faculta\An 3 Sem 2\SCS\image.txt", read_mode);
    readline(read_file,file_line);
    read(file_line, rows);
    read(file_line, cols);
    row<=rows;
    col<=cols;

    for i in 0 to rows-1 loop
        readline(read_file,file_line);
        for j in 0 to cols-1 loop
                read(file_line, read_value);
                data(i,j)<=read_value;
        end loop;
    end loop;



    test<=data(0,0);
    last_elem<=test;

    file_close(read_file);
    end process;

end Behavioral;

Solution

  • Providing a Minimal, Complete, and Verifiable example for your code:

    library ieee;
    use ieee.std_logic_1164.all;
    use std.textio.all;
    
    entity main is
        port (
            rstb:       in  std_logic;
            clk:        in  std_logic;
            row:        out integer;
            col:        out integer;
            last_elem:  out integer
        );
    end entity main;
    
    architecture behavioral of main is
        -- type matrixdata is array (0 to 240, 0 to 217) of integer;
        type matrixdata is array (0 to 3, 0 to 2) of integer;
        signal data:    matrixdata;
        signal test:    integer;
    
    begin
        process (clk)
            file read_file:         text;
            variable file_line:     line;
            variable row_counter:   integer := 0;
            variable rows:          integer;
            variable cols:          integer;
            variable read_value:    integer;
        begin
            --file_open(read_file, "d:\faculta\an 3 sem 2\scs\image.txt", read_mode);
            file_open (read_file, "image.txt", read_mode);
            readline (read_file, file_line);
            read (file_line, rows);
            read (file_line, cols);
            row <= rows;
            col <= cols;
    
            for i in 0 to rows - 1 loop
                readline (read_file, file_line);
                for j in 0 to cols - 1 loop
                        read(file_line, read_value);
                        data(i,j) <= read_value;
                end loop;
            end loop;
    
            test <= data(0, 0);
            last_elem <= test;
    
            file_close(read_file);
        end process;
    end behavioral;
    
    library ieee;
    use ieee.std_logic_1164.all;
    
    entity main_tb is
    end entity;
    
    architecture foo of main_tb is
        component main is
            port (
                rstb:       in  std_logic;
                clk:        in  std_logic;
                row:        out integer;
                col:        out integer;
                last_elem:  out integer
            );
        end component main;
        signal rstb:       std_logic := '1';
        signal clk:        std_logic := '0';
        signal row:        integer;
        signal col:        integer;
        signal last_elem:  integer;
    begin
    DUT:
        main
            port map (
                rstb => rstb,
                clk => clk,
                row => row,
                col => col,
                last_elem => last_elem
            );
    WAVEFORM_DISPLAY_STIMULUS:
        process
        begin
            wait for 0 ns;
            wait for 1 ns;
            wait;
        end process;
    end architecture;
    

    Modified for a smaller two dimensional matrixdata type and supplied with a an input file:

    images.txt

    4 3
    0 0 0
    1 1 1
    2 2 2
    3 3 3
    

    We see:

    main_tb.jpg

    Where the matrix values appear to be read in correctly. The last_elem signal has the default value (INTEGER'LOW, -2147483648) as does test, both declarations lacking an initial value.

    Neither Data nor test are in the process sensitivity list assignments will not occur in the same simulation cycle an assignment is scheduled. Every process executes at least once.

    There's also an issue with the process sensitivity list. The process will execute for each event on clk, repetitively opening the file, reading in data and closing the file.

    The proper fix for these two issues would be to remove the process sensitivity list and add a final wait statement (wait;) after the file_close. Also add a wait statement with zero incremental simulation time (e.g. wait for 0 ns;) prior to each signal assignment depending on a previous signal assignment value in the process.

    There's also the issue of error detection during TEXTIO operations (file_open, read_line). You've gone to all the trouble to close the file. How about checking for a successful file open and ENDFILE before executing procedure read_line?

    
        process
            file read_file:         text;
            variable file_line:     line;
            variable row_counter:   integer := 0;
            variable rows:          integer;
            variable cols:          integer;
            variable read_value:    integer;
            variable open_status:   FILE_OPEN_STATUS; -- ADDED
        begin
            --file_open(read_file, "d:\faculta\an 3 sem 2\scs\image.txt", read_mode);
            -- file_open (read_file, "image.txt", read_mode);
            file_open (open_status, read_file, "image.txt", read_mode);
    
            case open_status is  -- ADDED
                 when OPEN_OK =>
                    report "read_file opened for read" severity NOTE;
                when STATUS_ERROR =>
                    report "read_file already open" severity FAILURE;
                when NAME_ERROR =>
                    report "read_file file name not found" severity FAILURE;
                when MODE_ERROR =>
                    report "read_file can't be opened for read" severity FAILURE;
            end case;
    
            if endfile(read_file) then  -- ADDED
                report "can't read first line from read_file"
                severity FAILURE;
            end if;
            readline (read_file, file_line);
            read (file_line, rows);
            read (file_line, cols);
            row <= rows;
            col <= cols;
    
            for i in 0 to rows - 1 loop
                if endfile(read_file) then   -- ADDED
                    report "can't read line for all rows from read_file"
                    severity FAILURE;
                end if;
                readline (read_file, file_line);
                for j in 0 to cols - 1 loop
                        read(file_line, read_value);
                        data(i,j) <= read_value;
                end loop;
            end loop;
            wait for 0 ns;  --  ADDED causes a delta cycle, data is updated
            test <= data(0, 0);
            wait for 0 ns;  -- ADDED causes a delta cycle, test is updated
            last_elem <= test;
            file_close(read_file);
            wait;           -- ADDED
        end process;
    

    This loads the array once at initialization and last_elem value will be updated after successive delta simulation cycles.

    A wait statement causes an executing process to suspend until a condition is met. A wait statement without a condition assumes a timeout clause of TIME'HIGH.

    A wait statement with a timeout clause (here 0 ns for the first two) will suspend the process until the condition is met. The incremental delay is equivalent to the current simulation time plus the time expression.

    Because there's a further event scheduled for the current simulation time, a delta simulation cycle will occur in which the process resumes. At the beginning of each simulation cycle projected output waveform values scheduled for the current simulation time cause signal updates where the effective value of the signal can be evaluated (as in an assignment statement). This will occur for both of the first two wait statements.

    Hitting the final wait statement without a timeout clause assume a timeout clause of TIME'HIGH, the process won't resume again during simulation.

    You can prove the open_status and endfile tests work by manipulating the host file system (path and permissions) and image.txt file contents.

    With an additional change to the testbench:

    CLOCK:
        process
        begin
            wait for 5 ns;
            clk <= not clk;
            if now > 40 ns then
                wait;
            end if;
        end process;
    -- WAVEFORM_DISPLAY_STIMULUS:
    --     process
    --     begin
    --         wait for 0 ns;
    --         wait for 1 ns;
    --         wait;
    --     end process;
    

    You can demonstrate the code appears functional through simulation:

    main_tb_fixed.jpg

    When simulating you'll only start the process at the first line once, only resume twice waiting on signal updates and only get one message from

                    report "read_file opened for read" severity NOTE; 
    

    when evaluating open_status.

    As Tricky points out in a comment test is assigned the value of Data(0, 0) which is then assigned to last_element and actually contains the first element of the matrix.