Search code examples
imageiovhdl

how to read image file and convert it to bits in vhdl


I am trying to read an image file using textio package in vhdl. If i open an .jpg with notepad , i will get some junk data but actually it is ASCII data . Here i am trying to read these ascii data and convert them into bytes.

below is my code:

library ieee;
use ieee.std_logic_1164.all;
use std.textio.all;
use ieee.std_logic_textio.all;

entity file_io is

 port (
     clk:             in  std_logic;
     Data:            out std_logic_vector(7 downto 0)
 );
 end entity;

 architecture behav of file_io is

signal test_data : std_logic_vector(7 downto 0);
use ieee.numeric_std.all; 
use std.textio.all;
use ieee.std_logic_textio.all;
begin

File_reader:process(clk)
    file f    : text open read_mode is "C:\Users\Public\Pictures\Sample Pictures\Chrysanthemum.jpg";
    variable L:   line;
    variable var_int:   integer:= 0;
    variable var_char:   character;  

begin

if rising_edge(clk) then
        while not endfile(f) loop
                 readline(f, L);
         read(L, var_char);
         var_int := character'pos(var_char);
         test_data  <= std_logic_vector(to_unsigned(var_int, test_data'length));  
        end loop;
     end if;
    Data <= test_data;
  end process;
end architecture behav;

testbench:

LIBRARY ieee;
use ieee.std_logic_1164.ALL;
use std.textio.all;

ENTITY file_io_test IS 
END file_io_test;

ARCHITECTURE behavior OF file_io_test IS
use work.io.all;
    signal clk:         std_logic := '0';
    signal Data: std_logic_vector(7 downto 0);

    -- Clock period definitions
    constant clk_period : time := 10 ns;

    BEGIN
      -- Instantiate the Unit Under Test (UUT)
    UUT:
     entity work.file_io(behav)
    port map (
           clk => clk,
        Data => Data
          );

    -- Clock process definitions( clock with 50% duty cycle is generated here.
     clk_process :process
       begin
         clk <= '1';
         wait for clk_period/2;  --for 5 ns signal is '1'.
          clk <= '0';
         wait for clk_period/2;  --for next 5 ns signal is '0'.

     end process;
    end behavior;  

I am getting only one byte in waveform. expected result is : Every clock cycle new character should be rread and new byte should be obtained.

below is waveform: enter image description here

below is the image I am trying to read: enter image description here


Solution

  • The question has a fundamental flaw. You can't use textio to read binary values, it's for text.

    See IEEE Std 1076-2008 16.4 Package TEXTIO paragraphs 3 (in part) and 4:

    Procedures READLINE, WRITELINE, and TEE declared in package TEXTIO read and write entire lines of a file of type TEXT. Procedure READLINE causes the next line to be read from the file and returns as the value of parameter L an access value that designates an object representing that line. If parameter L contains a non-null access value at the start of the call, the procedure may deallocate the object designated by that value. The representation of the line does not contain the representation of the end of the line. ...

    The language does not define the representation of the end of a line. An implementation shall allow all possible values of types CHARACTER and STRING to be written to a file. However, as an implementation is permitted to use certain values of types CHARACTER and STRING as line delimiters, it might not be possible to read these values from a TEXT file.

    And that can be demonstrated with your Chrysanthemum.jpg:

    Chrsanthemum read failure

    It is possible in VHDL to read raw characters one at a time (matching your need).

    See IEEE Std 1076-2008 5.5 File types: 5.5.jpg 5.5 cont.jpg

    So all we have to do is declare a file type and we get these procedures defined implicitly.

    We can use them to invoke raw read, without any end of line issues caused by textio:

    library ieee;
    use ieee.std_logic_1164.all;
    
    entity file_io is
        port (
            clk:    in  std_logic;
            Data:   out std_logic_vector(7 downto 0);
            done:   out boolean
     );
     end entity;
    
    architecture foo of file_io is
        use ieee.numeric_std.all;
    begin
    
    File_reader:
        process (clk)
            -- "C:\Users\Public\Pictures\Sample Pictures\Chrysanthemum.jpg";
            constant filename:  string := "Chrysanthemum.jpg"; -- local to sim
            variable char_val:  character;
            variable status: FILE_OPEN_STATUS;
            variable openfile:  boolean;  -- FALSE by default
            type f is file of character;
            file ffile: f;
            variable char_count:    natural := 0;
        begin
            if rising_edge (clk) then
                if not openfile then
                    file_open (status, ffile, filename, READ_MODE);
                    if status /= OPEN_OK then
                        report "FILE_OPEN_STATUS = " & 
                                FILE_OPEN_STATUS'IMAGE(status)
                        severity FAILURE;
                    end if;
                    report "FILE_OPEN_STATUS = " & FILE_OPEN_STATUS'IMAGE(status);
                    openfile := TRUE;
                else 
                    if not endfile(ffile) then
                        read(ffile, char_val);
                        -- report "char_val = " & character'image(char_val);
                        char_count := char_count + 1;
                        Data  <= std_logic_vector (
                                 to_unsigned(character'pos(char_val),
                                 Data'length) );
                     end if;
                     if endfile(ffile) then  -- can occur after last character
                        report "ENDFILE, read " & 
                              integer'image(char_count) & "characters";
                        done <= TRUE;
                        FILE_CLOSE(ffile);
                    end if;
                end if;
            end if;
        end process;
    end architecture foo;
    
    library ieee;
    use ieee.std_logic_1164.all;
    
    entity file_io_test is 
    end file_io_test;
    
    architecture behavior of file_io_test is
        signal clk:         std_logic := '0';
        signal data:        std_logic_vector(7 downto 0);
        signal done:        boolean;
        constant clk_period: time := 10 ns;
    begin
    uut:
        entity work.file_io(foo)
            port map (
               clk => clk,
               data => data,
               done => done
            );
            
    clk_process:
        process
        begin
            if not done then
                 clk <= '1';
                 wait for clk_period/2;
                  clk <= '0';
                 wait for clk_period/2;
             else
                 wait;
             end if;
         end process;
    end architecture behavior;  
    

    Now we can have all the characters than can delimit a line show up in our read:

    file_io_test_char_raw.png

    Note that package std.textio is not made visible through any context item.