Добавить постоянный элемент массива через тестовый стенд

В настоящее время я изучаю моделирование ПЗУ с использованием VHDL. Прямо сейчас я смоделировал ПЗУ 32x8 и создал его как пустой массив cons в моем основном модуле, потому что я планирую импортировать файл через код тестового стенда, который содержит данные в каждой строке. Мой вопрос: после импорта и чтения строки из файла, как вы должны добавить этот сигнал в компонент ПЗУ? Мой текущий код для моего тестового стенда выглядит следующим образом:

library IEEE;
use IEEE.Std_logic_1164.all;
use IEEE.STD_LOGIC_ARITH.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
use STD.textio.all;
use IEEE.STD_LOGIC_textio.all;

entity ROM_tb is
end;

architecture bench of ROM_tb is

  component ROM
      Port ( 
             address : in STD_LOGIC_VECTOR (4 downto 0);
             data : out STD_LOGIC_VECTOR(7 downto 0));
  end component;

  signal address: STD_LOGIC_VECTOR (4 downto 0);
  signal data: STD_LOGIC_VECTOR(7 downto 0);
  signal content : STD_LOGIC_VECTOR(7 downto 0); -- signal file content holder

   -- file objects instantiation
  file file_VECTORS : text;

begin

  uut: ROM port map ( address => address,
                      data    => data );

  stimulus: process
  --file objects declarations
  variable f_LINE      : line; -- file pointer
  variable f_CONTENT    : STD_LOGIC_VECTOR(7 downto 0); -- file content holder
  variable f_i          : INTEGER := 0; -- ROM MA location index
  
  variable i : INTEGER := 0;
  
  begin
  
    file_open(file_VECTORS, "ROM-data.txt", read_mode);
    
    while not endfile(file_VECTORS) loop
        readline(file_VECTORS, f_LINE);
        read(f_LINE, f_CONTENT);
        
        content <= f_content;

        --ROM(f_i) <= content; I was hoping to do something like this...
        
        f_i := f_i + 1;
    end loop;
  
        while i < 32 loop
           wait for 35 ns;
           address <= conv_STD_LOGIC_VECTOR(i, 5);
           i := i+1;
        end loop;
        
    wait;
  end process;

end;

Я создал необходимые файловые объекты и обработал цикл while, который будет считывать мои 8-битные данные в каждой строке. Для каждой строки я планирую передать содержимое переменной сигналу, и этот сигнал сохранит его в массиве ПЗУ, и я не уверен, как это сделать.


person Guorishix    schedule 27.03.2021    source источник
comment
Если вам удалось решить вашу проблему, опубликуйте свое решение в качестве ответа и примите его по истечении тайм-аута. Не ставьте (неполное) решение в свой вопрос.   -  person Mark Rotteveel    schedule 27.03.2021


Ответы (2)


Без объекта и архитектуры для ПЗУ, а также содержимого ROM_data.txt ваш вопрос и ответ не могут быть проверены. Помимо ПЗУ, содержащегося в массиве значений сигналов или переменных в нераскрытой архитектуре ПЗУ, в любом месте, где набор инструментов позволит вам указать начальное значение ОЗУ или значение ПЗУ программно (например, Xilinx, а не Intel), вы также можете использовать нечистая функция для предоставления значения константы типа массива в объявлении:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;  -- to_integer instead of std_logic_arith conv_integer
use ieee.math_real.all;   -- for ceiling, log2

entity rom is  -- generic ROM with std_logic_vector address and output
    generic (  -- default values supplied for plugin to OPs usage
            filename:       string := "ROM_DATA.txt";
            rom_width:      natural := 8;
            rom_depth:      natural := 32
    );
    port ( 
        address:    in  std_logic_vector 
            (integer(ceil(log2(real(rom_depth)))) - 1 downto 0);
        data:       out std_logic_vector (rom_width - 1 downto 0)
    );
end entity;

architecture foo of rom is
    type rom_array is array
        (0 to rom_depth - 1) of std_logic_vector (rom_width - 1 downto 0);
    impure function initromfromfile (romfilename: in string) 
                return rom_array is
        use std.textio.all;
        file romfile:  text open read_mode is romfilename; 
        variable romfileline:   line;
        variable vrom:           rom_array;
        variable rom_value:     bit_vector(7 downto 0);
    begin 
        for i in vrom'range loop  -- contents of file are ordered
            if endfile(romfile) then   -- file can be shorter than rom array
                vrom(i) := (others => '0');
            else
                readline(romfile, romfileline); -- 1 datum per line
                read(romfileline, rom_value);
                vrom(i) := to_stdlogicvector(rom_value);
            end if;
        end loop;
        return vrom;
    end function;
    constant romval: rom_array := initromfromfile(filename);
begin
    data <= romval(to_integer(unsigned(address)));   -- read 
end architecture;

Здесь есть значения по умолчанию для универсального ПЗУ по ширине, глубине и имени файла инициализации.

Для файла ROM_DATA.txt:

11111110
11101101
11111010
11001110
11011110
10101101
10111110
11101111

который имеет меньше значений данных, чем размер массива ПЗУ, остальные значения будут заполнены нулями.

Инициализация выполняется в объявлении объекта, содержащего значение ROM (и тип массива).

Функционал можно легко протестировать:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity rom_tb is
end entity;

architecture foo of rom_tb is
    signal address:     std_logic_vector (4 downto 0);
    signal data:        std_logic_vector (7 downto 0);
    -- for IEEE Std 1076 revisions earlier than 2008:
    function to_string (inp: std_logic_vector) return string is
        variable image_str: string (1 to inp'length);
        alias input_str:  std_logic_vector (1 to inp'length) is inp;
    begin
        for i in input_str'range loop
            image_str(i) := character'VALUE(std_ulogic'IMAGE(input_str(i)));
        end loop;
        return image_str;
    end function;
begin
ROM0:
    entity work.rom  -- no generic map and generic values will default
        port map (
            address => address,
            data => data
        );
ROM_DUMP:
    process
    begin
        for i in 0 to 2 ** address'length - 1 loop
            address <= std_logic_vector (to_unsigned(i, address'length));
            wait for 0 ns; -- delta cycle for address to update
            wait for 0 ns; -- delta cycle for data to update
            report "rom(" & integer'image(i) & ") = " & to_string(data);
        end loop;
        wait;
    end process;
end architecture;

При запуске:

ghdl -a rom.vhdl
ghdl -e rom_tb
ghdl -r rom_tb
../../src/ieee/v93/numeric_std-body.vhdl:2098:7:@0ms:(assertion warning): NUMERIC_STD.TO_INTEGER: metavalue detected, returning 0
rom.vhdl:80:13:@0ms:(report note): rom(0) = 11111110
rom.vhdl:80:13:@0ms:(report note): rom(1) = 11101101
rom.vhdl:80:13:@0ms:(report note): rom(2) = 11111010
rom.vhdl:80:13:@0ms:(report note): rom(3) = 11001110
rom.vhdl:80:13:@0ms:(report note): rom(4) = 11011110
rom.vhdl:80:13:@0ms:(report note): rom(5) = 10101101
rom.vhdl:80:13:@0ms:(report note): rom(6) = 10111110
rom.vhdl:80:13:@0ms:(report note): rom(7) = 11101111
rom.vhdl:80:13:@0ms:(report note): rom(8) = 00000000
rom.vhdl:80:13:@0ms:(report note): rom(9) = 00000000
rom.vhdl:80:13:@0ms:(report note): rom(10) = 00000000
rom.vhdl:80:13:@0ms:(report note): rom(11) = 00000000
rom.vhdl:80:13:@0ms:(report note): rom(12) = 00000000
rom.vhdl:80:13:@0ms:(report note): rom(13) = 00000000
rom.vhdl:80:13:@0ms:(report note): rom(14) = 00000000
rom.vhdl:80:13:@0ms:(report note): rom(15) = 00000000
...
rom.vhdl:80:13:@0ms:(report note): rom(31) = 00000000

Вы можете видеть, что ПЗУ было инициализировано и доступно в момент времени 0 (после обработки).

Предупреждение исходит от адреса, не имеющего значения по умолчанию, которое может быть интерпретировано как двоичное число (все буквы «U») во время инициализации. После назначения адреса предупреждение больше не появляется.

Использование пакета IEEE numeric_std вместо пакета Synopsys std_logic_arith учитывает, что пакет IEEE поддерживается (и расширяется по редакциям), а пакет Synopsys — нет.

Использование переменной bit_vector позволяет использовать std.standard.read без обращения к пакету Synopsys std_logic_textio.

IEEE Std 1076-2008 и более поздние версии предоставляют пакет std_logic_1164, который предоставляет процедуру READ, совместимую с подтипами std_logic_vector, а также восьмеричные и шестнадцатеричные процедуры чтения. Редакции -2008 и более поздние также предоставляют предопределенные функции to_string для всех типов одномерных массивов, а также пакеты IEEE numeric_std_unsigned, заменяющие пакет Synopsys std_logic_unsigned.

Объявление универсального ПЗУ позволяет поддерживать другие размеры ПЗУ, предоставляя значения глубины и ширины. Общая константа, предоставленная для имени файла, позволяет поддерживать несколько ПЗУ с использованием разных имен файлов.

Существует несколько различных способов предоставления начальных значений для ПЗУ и ОЗУ, доступных для vhdl в Stackoverflow по поиску.

Как правило, постоянное запоминающее устройство (ПЗУ) не должно быть доступно для записи.

person Community    schedule 27.03.2021
comment
Можно ли реализовать нечистую функцию для инициализации значений ПЗУ через тестовый стенд? - person Guorishix; 28.03.2021

Я не знаю, есть ли другие способы, но я решил свою проблему, просто добавив контакт r/w к моему основному модулю и просто передав содержимое из тестового стенда, установив r/w на НИЗКИЙ уровень, и выполняя чтение на ВЫСОКИЙ. Достаточно просто. Надеюсь, это поможет будущим дизайнерам.

library IEEE;
use IEEE.Std_logic_1164.all;
use IEEE.STD_LOGIC_ARITH.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
use STD.textio.all;
use IEEE.STD_LOGIC_textio.all;

entity ROM_tb is
end;

architecture bench of ROM_tb is

  component ROM
      Port ( 
             rd      : in STD_LOGIC;
             data_in   : in STD_LOGIC_VECTOR (7 downto 0);      
             address : in STD_LOGIC_VECTOR (4 downto 0);
             data_out : out STD_LOGIC_VECTOR(7 downto 0));
  end component;

  signal rd: STD_LOGIC;
  signal data_in: STD_LOGIC_VECTOR (7 downto 0);
  signal address: STD_LOGIC_VECTOR (4 downto 0);
  signal data_out: STD_LOGIC_VECTOR(7 downto 0);
  
  signal content : STD_LOGIC_VECTOR(7 downto 0);

   -- file objects instantiation
  file file_VECTORS : text;

begin

  uut: ROM port map ( 
                      rd        => rd,
                      data_in   => data_in,
                      address   => address,
                      data_out  => data_out );

  stimulus: process
  --file objects declarations
  variable f_LINE      : line;
  variable f_CONTENT    : STD_LOGIC_VECTOR(7 downto 0);
  variable f_i          : INTEGER := 0;
  
  variable i : INTEGER := 0;
  
  begin
  
    file_open(file_VECTORS, "ROM_data.txt", read_mode);
    
    while not endfile(file_VECTORS) loop
        readline(file_VECTORS, f_LINE);
        read(f_LINE, f_CONTENT);
        content <= f_CONTENT;
        
        rd <= '0';
        data_in <= content;
        address <= conv_STD_LOGIC_VECTOR(f_i, 5);
        
        f_i := f_i + 1;
        wait for 35 ns;
    end loop;
  
        while i < 32 loop
           wait for 35 ns;
           rd <= '1';
           address <= conv_STD_LOGIC_VECTOR(i, 5);
           i := i+1;
        end loop;
        
    wait;
  end process;

end;
person Guorishix    schedule 27.03.2021