VHDL数组——如何声明一个未知大小的数组并使用它。

时间:2021-07-13 20:57:18

My requirement is to read data bits from input file and write data into memory array(output) in vhdl. As i am not aware of the amount of data in input file, i need to declare array of unknown size and assign data to memory at later stages.

我的要求是读取输入文件中的数据位,并将数据写入到vhdl中的内存数组(输出)中。由于我不知道输入文件中的数据量,所以需要声明未知大小的数组,并在稍后的阶段将数据分配给内存。

My code is as below:

我的代码如下:

Declarations :

声明:

PACKAGE io IS
   type memory is array (natural range<>) of std_logic_vector(3 downto 0); 
END;

entity File_io is
 port (
     clk:             in  std_logic;
     Data_memory:     out   memory
 );
end entity;

architecture behav of File_io is
 signal mem: memory;
begin
 process(clk)
   begin
     for i in 0 to 15 loop  -- Took just 16 values for explaination purpose.
                             -- i may need more values to be written which is unknown.
      mem(i) <= std_logic_vector(to_unsigned(i, 4));
     end loop;
    Data_memory <= mem;
  end process;
end architecture behav;

I have minimized the actual code to exact requiremnet of mine. Ignore if any syntax errors.

我已经最小化了实际代码,以准确地确定我的需求。忽略任何语法错误。

The problem is I can not assign values to array which is unconstrained, that is of undefined size. How do i do this ? any suggestions or alternatives? Guide me

问题是我不能为无约束的,无定义大小的数组赋值。我该怎么做呢?任何建议或选择呢?引导我

2 个解决方案

#1


2  

Looking at your other question - How to Eliminate whitespaces while Reading a file in VHDL provides an example memory init file as well as a problem reading it.

查看您的另一个问题——如何在读取VHDL中的文件时消除空白,这提供了一个示例内存初始化文件以及读取它的问题。

Incorporating that fix and using the method method J.H. Bonarius suggests gives rise to a Minimal, Complete and Verifiable example:

结合这一修复并使用J.H.博纳留斯建议的方法,产生了一个最小的、完整的、可验证的示例:

library ieee;
use ieee.std_logic_1164.all;

PACKAGE io IS
   type memory is array (natural range<>) of std_logic_vector(3 downto 0); 
   function iswhitespace (inpstr: in string) return boolean;
END;

package body io is
    function iswhitespace (inpstr:  in  string) return boolean is
        constant NBSP: character  := character'val(128); 
    begin
        for i in inpstr'range loop
            if inpstr(i) /= ' ' and inpstr(i) /= NBSP and inpstr(i) /= HT then
                exit;
            elsif i = inpstr'RIGHT then
                return TRUE;
            end if;
        end loop;
        return FALSE;
    end function;
end package body;

library ieee;
use ieee.std_logic_1164.all;
use work.io.all;

entity File_io is
    generic (
        constant MEMORY_SIZE: natural := 42;
        constant filename:  string := "C:\Users\ChowdaryS\Downloads\topo.bin"
    );
     port (
         clk:             in  std_logic;
         Data_memory:     out   memory (0 to MEMORY_SIZE - 1) 
     );
end entity;

architecture foo of File_io is
    signal mem: memory (0 to MEMORY_SIZE - 1); -- ADDED subtype indication
    use ieee.numeric_std.all;                  -- MISSING cntext item
    use std.textio.all;
    signal mem_inited:     boolean := FALSE;   -- ADDED
begin
    process(clk)
        file f:       text open read_mode is filename;
        variable L:   line;
        variable i:   integer:= 0;
        variable b:   bit_vector(3 downto 0);  
    begin
        if not mem_inited then
            i := 0;
            while not endfile(f) loop
                readline(f, L);
                while L.all'length >= b'length and not iswhitespace(L.all) loop
                    read(L, b);
                    mem(i) <= to_stdlogicvector(b);
                    i := i + 1;
                end loop;
            end loop;
            report "mem values loaded = " &  integer'image(i);
            mem_inited <= TRUE;
        end if;
    end process;
    Data_memory <= mem;
end architecture foo;

There are a changes. A function iswhitespace has been added to package io. You can see the above cited question for trade-offs and whether it's required.

有变化。将函数iswhitespace添加到包io中。您可以看到上面提到的权衡问题,以及是否需要它。

The assignment to the output port has been moved outside the process. It's assumed you'll have some sort of writes to mem included in the process.

将分配给输出端口的任务移动到流程之外。假设您将在过程中对mem进行某种写入。

There's also a testbench that instantiates file_io and determines the size of the memory array, passing that as a generic.

还有一个testbench来实例化file_io并确定内存数组的大小,并将其作为泛型传递。

library ieee;
use ieee.std_logic_1164.all;
use work.io.all;

entity file_io_tb is
end entity;

architecture foo of file_io_tb is

    constant MEMSIZ:    natural := 16;
    constant filename:  string := "topo.bin";  -- found locally.
    signal clk:         std_logic := '0';
    signal Data_memory: memory (0 to MEMSIZ - 1);
    use std.textio.all;

    impure function getarraysize return natural is
        variable L:     Line;
        variable i:     natural;
        variable b:     bit_vector (3 downto 0);
        file f:         text  open read_mode is filename;
    begin
        i := 0;
        while not endfile(f) loop
            readline(f, L);
            while L.all'length >= b'length and not iswhitespace(L.all) loop
                read(L, b);
                i := i + 1;
            end loop;
        end loop;
        report " memory size = " & integer'image(i);
        return i;
    end function;
begin
DUT:
    entity work.file_io
        generic map (MEMORY_SIZE => getarraysize, filename => filename)
        port map (
            clk => clk,
            Data_memory => Data_memory
        );

CLOCK:
    process
    begin
        wait for 10 ns;
        clk <= not clk;
        if now > 50 ns then
            wait;
        end if;
    end process;

end architecture;

The function is performs the file read at elaboration time to set a generic.

该函数执行精化时读取的文件来设置泛型。

And we see this initializes mem:

我们看到它初始化了mem

VHDL数组——如何声明一个未知大小的数组并使用它。

The copy of topo.bin used has four trailing spaces on the first line:

威尼斯平底渔船的副本。bin used在第一行有四个尾随空格:

10101100 11010100 10101100 11010100   

11111110 10111001 11111110 10111001

The values shown in the waveform match the above two lines from topo.bin.

波形中显示的值与topo.bin中的两行匹配。

(And all this got written to find the issue with whitespace in the other question).

(所有这些都是为了在另一个问题中找到空格的问题而写的)。

#2


2  

Read the file twice and determine the amount of lines the first time. For example

两次读取文件,第一次确定行数。例如

edit: finally had access to a vhdl simulator. Fixed the code. I've been switching between VHDL, C++, C#, matlab and python so much lately, that I keep mixing syntaxes.

编辑:终于可以访问vhdl模拟器了。固定的代码。我最近经常在VHDL、c++、c#、matlab和python之间切换,我一直在混合语法。

library IEEE;
use IEEE.std_logic_1164.all;
use std.textio.all;

entity file_io is
    generic (
        data_width : positive := 4;
        file_name  : string
    );
    port (
        clk         :  in std_logic;
        file_output : out std_logic_vector(data_width-1 downto 0) := (others => '0')
    );
end entity file_io;

architecture behaviour of file_io is
    impure function get_line_count return positive is
        file file_pointer : text;
        variable line_data : line;
        variable lineCount : natural := 0;
    begin
        file_open(file_pointer, file_name, read_mode);
        while not endfile(file_pointer) loop
            readline(file_pointer, line_data);
            lineCount := lineCount + 1;
        end loop;
        file_close(file_pointer);
        return lineCount;
    end function get_line_count;

    constant memory_size : positive := get_line_count;

    subtype data_type is std_logic_vector(data_width-1 downto 0);
    type memory_type is array (0 to memory_size-1) of data_type;

    impure function get_data return memory_type is
        file file_pointer : text;
        variable line_data : line;
        variable line_value : bit_vector(data_width-1 downto 0);
        variable memory : memory_type;
        variable index : natural := 0;
    begin
        file_open(file_pointer, file_name, read_mode);
        while not endfile(file_pointer) loop
            readline(file_pointer, line_data);
            read(line_data, line_value);
            memory(index) := to_stdlogicvector(line_value);
            index := index + 1;
        end loop;
        file_close(file_pointer);
        return memory;
    end function get_data;

    constant memory : memory_type := get_data;
    signal index : natural := 0;
begin
    process(clk)
    begin
        if rising_edge(clk) then
            file_output <= memory(index);
            if (index < memory_size-1) then
                index <= index + 1;
            else
                index <= 0;
            end if;
        end if;
    end process;
end architecture behaviour;

and test bench:

和实验台:

library IEEE;
use IEEE.std_logic_1164.all;

entity file_io_tb is
end entity file_io_tb;

architecture behaviour of file_io_tb is
    signal clk : std_logic := '0';
    constant data_width : positive := 4;
    signal data : std_logic_vector(data_width-1 downto 0);
begin
    file_io_inst : entity work.file_io
        generic map(
            data_width => 4,
            file_name => "data_file.txt"
            )
        port map(
            clk => clk,
            file_output => data
            );

    clk_prc : process
    begin
        loop
            clk <= '0', '1' after 1 ns;
            wait for 2 ns;
        end loop;
    end process;
end architecture behaviour;

data_file.txt just contains

data_file。三只包含

0101
1010
1100
0011
...

this works fine for me...

这对我来说没问题……

#1


2  

Looking at your other question - How to Eliminate whitespaces while Reading a file in VHDL provides an example memory init file as well as a problem reading it.

查看您的另一个问题——如何在读取VHDL中的文件时消除空白,这提供了一个示例内存初始化文件以及读取它的问题。

Incorporating that fix and using the method method J.H. Bonarius suggests gives rise to a Minimal, Complete and Verifiable example:

结合这一修复并使用J.H.博纳留斯建议的方法,产生了一个最小的、完整的、可验证的示例:

library ieee;
use ieee.std_logic_1164.all;

PACKAGE io IS
   type memory is array (natural range<>) of std_logic_vector(3 downto 0); 
   function iswhitespace (inpstr: in string) return boolean;
END;

package body io is
    function iswhitespace (inpstr:  in  string) return boolean is
        constant NBSP: character  := character'val(128); 
    begin
        for i in inpstr'range loop
            if inpstr(i) /= ' ' and inpstr(i) /= NBSP and inpstr(i) /= HT then
                exit;
            elsif i = inpstr'RIGHT then
                return TRUE;
            end if;
        end loop;
        return FALSE;
    end function;
end package body;

library ieee;
use ieee.std_logic_1164.all;
use work.io.all;

entity File_io is
    generic (
        constant MEMORY_SIZE: natural := 42;
        constant filename:  string := "C:\Users\ChowdaryS\Downloads\topo.bin"
    );
     port (
         clk:             in  std_logic;
         Data_memory:     out   memory (0 to MEMORY_SIZE - 1) 
     );
end entity;

architecture foo of File_io is
    signal mem: memory (0 to MEMORY_SIZE - 1); -- ADDED subtype indication
    use ieee.numeric_std.all;                  -- MISSING cntext item
    use std.textio.all;
    signal mem_inited:     boolean := FALSE;   -- ADDED
begin
    process(clk)
        file f:       text open read_mode is filename;
        variable L:   line;
        variable i:   integer:= 0;
        variable b:   bit_vector(3 downto 0);  
    begin
        if not mem_inited then
            i := 0;
            while not endfile(f) loop
                readline(f, L);
                while L.all'length >= b'length and not iswhitespace(L.all) loop
                    read(L, b);
                    mem(i) <= to_stdlogicvector(b);
                    i := i + 1;
                end loop;
            end loop;
            report "mem values loaded = " &  integer'image(i);
            mem_inited <= TRUE;
        end if;
    end process;
    Data_memory <= mem;
end architecture foo;

There are a changes. A function iswhitespace has been added to package io. You can see the above cited question for trade-offs and whether it's required.

有变化。将函数iswhitespace添加到包io中。您可以看到上面提到的权衡问题,以及是否需要它。

The assignment to the output port has been moved outside the process. It's assumed you'll have some sort of writes to mem included in the process.

将分配给输出端口的任务移动到流程之外。假设您将在过程中对mem进行某种写入。

There's also a testbench that instantiates file_io and determines the size of the memory array, passing that as a generic.

还有一个testbench来实例化file_io并确定内存数组的大小,并将其作为泛型传递。

library ieee;
use ieee.std_logic_1164.all;
use work.io.all;

entity file_io_tb is
end entity;

architecture foo of file_io_tb is

    constant MEMSIZ:    natural := 16;
    constant filename:  string := "topo.bin";  -- found locally.
    signal clk:         std_logic := '0';
    signal Data_memory: memory (0 to MEMSIZ - 1);
    use std.textio.all;

    impure function getarraysize return natural is
        variable L:     Line;
        variable i:     natural;
        variable b:     bit_vector (3 downto 0);
        file f:         text  open read_mode is filename;
    begin
        i := 0;
        while not endfile(f) loop
            readline(f, L);
            while L.all'length >= b'length and not iswhitespace(L.all) loop
                read(L, b);
                i := i + 1;
            end loop;
        end loop;
        report " memory size = " & integer'image(i);
        return i;
    end function;
begin
DUT:
    entity work.file_io
        generic map (MEMORY_SIZE => getarraysize, filename => filename)
        port map (
            clk => clk,
            Data_memory => Data_memory
        );

CLOCK:
    process
    begin
        wait for 10 ns;
        clk <= not clk;
        if now > 50 ns then
            wait;
        end if;
    end process;

end architecture;

The function is performs the file read at elaboration time to set a generic.

该函数执行精化时读取的文件来设置泛型。

And we see this initializes mem:

我们看到它初始化了mem

VHDL数组——如何声明一个未知大小的数组并使用它。

The copy of topo.bin used has four trailing spaces on the first line:

威尼斯平底渔船的副本。bin used在第一行有四个尾随空格:

10101100 11010100 10101100 11010100   

11111110 10111001 11111110 10111001

The values shown in the waveform match the above two lines from topo.bin.

波形中显示的值与topo.bin中的两行匹配。

(And all this got written to find the issue with whitespace in the other question).

(所有这些都是为了在另一个问题中找到空格的问题而写的)。

#2


2  

Read the file twice and determine the amount of lines the first time. For example

两次读取文件,第一次确定行数。例如

edit: finally had access to a vhdl simulator. Fixed the code. I've been switching between VHDL, C++, C#, matlab and python so much lately, that I keep mixing syntaxes.

编辑:终于可以访问vhdl模拟器了。固定的代码。我最近经常在VHDL、c++、c#、matlab和python之间切换,我一直在混合语法。

library IEEE;
use IEEE.std_logic_1164.all;
use std.textio.all;

entity file_io is
    generic (
        data_width : positive := 4;
        file_name  : string
    );
    port (
        clk         :  in std_logic;
        file_output : out std_logic_vector(data_width-1 downto 0) := (others => '0')
    );
end entity file_io;

architecture behaviour of file_io is
    impure function get_line_count return positive is
        file file_pointer : text;
        variable line_data : line;
        variable lineCount : natural := 0;
    begin
        file_open(file_pointer, file_name, read_mode);
        while not endfile(file_pointer) loop
            readline(file_pointer, line_data);
            lineCount := lineCount + 1;
        end loop;
        file_close(file_pointer);
        return lineCount;
    end function get_line_count;

    constant memory_size : positive := get_line_count;

    subtype data_type is std_logic_vector(data_width-1 downto 0);
    type memory_type is array (0 to memory_size-1) of data_type;

    impure function get_data return memory_type is
        file file_pointer : text;
        variable line_data : line;
        variable line_value : bit_vector(data_width-1 downto 0);
        variable memory : memory_type;
        variable index : natural := 0;
    begin
        file_open(file_pointer, file_name, read_mode);
        while not endfile(file_pointer) loop
            readline(file_pointer, line_data);
            read(line_data, line_value);
            memory(index) := to_stdlogicvector(line_value);
            index := index + 1;
        end loop;
        file_close(file_pointer);
        return memory;
    end function get_data;

    constant memory : memory_type := get_data;
    signal index : natural := 0;
begin
    process(clk)
    begin
        if rising_edge(clk) then
            file_output <= memory(index);
            if (index < memory_size-1) then
                index <= index + 1;
            else
                index <= 0;
            end if;
        end if;
    end process;
end architecture behaviour;

and test bench:

和实验台:

library IEEE;
use IEEE.std_logic_1164.all;

entity file_io_tb is
end entity file_io_tb;

architecture behaviour of file_io_tb is
    signal clk : std_logic := '0';
    constant data_width : positive := 4;
    signal data : std_logic_vector(data_width-1 downto 0);
begin
    file_io_inst : entity work.file_io
        generic map(
            data_width => 4,
            file_name => "data_file.txt"
            )
        port map(
            clk => clk,
            file_output => data
            );

    clk_prc : process
    begin
        loop
            clk <= '0', '1' after 1 ns;
            wait for 2 ns;
        end loop;
    end process;
end architecture behaviour;

data_file.txt just contains

data_file。三只包含

0101
1010
1100
0011
...

this works fine for me...

这对我来说没问题……