Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Industrial programming >> VHDL

Как инициализировать RAM из файла с помощью TEXTIO

Удобный способ заполнить блочную ОЗУ начальными значениями — прочитать двоичные или шестнадцатеричные литералы из файла ASCII. Это также хороший способ создать ПЗУ (постоянную память) на VHDL. В конце концов, ОЗУ и ПЗУ в ПЛИС — это одно и то же, ПЗУ — это ОЗУ, из которого вы только читаете.

В примерах в этой статье предполагается, что следующие константы и тип ОЗУ были объявлены в начале декларативной области файла VHDL.

constant ram_depth : natural := 256;
constant ram_width : natural := 32;

type ram_type is array (0 to ram_depth - 1)
  of std_logic_vector(ram_width - 1 downto 0);

Этот пост в блоге является частью серии статей об использовании библиотеки TEXTIO в VHDL. Прочтите другие статьи здесь:

Файл стимула считывается в тестовом стенде с помощью TEXTIO

Растровое изображение файла BMP, прочитанное с помощью TEXTIO

READLINE, LINE, HREAD, OREAD и BREAD

Подпрограммы и типы, необходимые для чтения и записи внешних файлов в VHDL, находятся в папке TEXTIO. упаковка. Этот пакет является частью std библиотека. Стандартная библиотека всегда загружена; поэтому нам не нужно явно импортировать его с помощью library ключевое слово.

Мы можем просто пойти дальше и использовать TEXTIO package в заголовке нашего файла VHDL следующим образом:

use std.textio.all;

Мы будем хранить данные ОЗУ в файле ASCII, где одна строка текста соответствует слоту памяти. Чтобы прочитать строку текста, мы используем READLINE процедура из TEXTIO упаковка. Процедура принимает два аргумента:имя файла в качестве константы и проанализированную строку текста в виде inout. переменная. Объявление прототипа READLINE процедура и LINE тип, взятый из стандартной спецификации VHDL, показан ниже.

procedure READLINE (file F: TEXT; L: inout LINE);

type LINE is access STRING; -- A LINE is a pointer
                            -- to a STRING value.

Хотя класс LINE параметр не указан явно в объявлении прототипа READLINE , это переменная, потому что это класс по умолчанию для inout параметры. LINE type — это просто тип доступа к строке, указатель на динамически выделяемый строковый объект.

VHDL-2008 определяет OREAD , HREAD и BREAD процедуры извлечения восьмеричных, шестнадцатеричных и двоичных значений из LINE объект. Методы чтения восьмеричных и шестнадцатеричных значений очень похожи, восьмеричные значения являются просто подмножеством шестнадцатеричных. Для простоты в этой статье мы пропустим восьмеричное чтение и сосредоточимся на том, как читать шестнадцатеричные и двоичные значения из текстового файла.

В приведенном ниже коде показаны актуальные для нас определения процедур, они доступны только в VHDL-2008 и более новых ревизиях. OREAD и HREAD процедуры бывают двух перегруженных разновидностей для каждого из поддерживаемых типов вывода. Необязательный GOOD вывод можно использовать для обнаружения ошибок чтения, хотя большинство инструментов выдает ошибку или предупреждение независимо от того, используется этот вывод или нет.

procedure OREAD (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR;
                                 GOOD : out BOOLEAN);
procedure OREAD (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR);

procedure HREAD (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR;
                                  GOOD : out BOOLEAN);
procedure HREAD (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR);

alias BREAD is READ [LINE, STD_ULOGIC_VECTOR, BOOLEAN];
alias BREAD is READ [LINE, STD_ULOGIC_VECTOR];
Щелкните здесь, чтобы просмотреть определения процедур ввода из библиотеки TEXTIO
procedure READLINE (file F: TEXT; L: inout LINE);

procedure READ (L: inout LINE; VALUE: out BIT;
                               GOOD: out BOOLEAN);
procedure READ (L: inout LINE; VALUE: out BIT);

procedure READ (L: inout LINE; VALUE: out BIT_VECTOR;
                               GOOD: out BOOLEAN);
procedure READ (L: inout LINE; VALUE: out BIT_VECTOR);

procedure READ (L: inout LINE; VALUE: out BOOLEAN;
                               GOOD: out BOOLEAN);
procedure READ (L: inout LINE; VALUE: out BOOLEAN);

procedure READ (L: inout LINE; VALUE: out CHARACTER;
                               GOOD: out BOOLEAN);
procedure READ (L: inout LINE; VALUE: out CHARACTER);

procedure READ (L: inout LINE; VALUE: out INTEGER;
                               GOOD: out BOOLEAN);
procedure READ (L: inout LINE; VALUE: out INTEGER);

procedure READ (L: inout LINE; VALUE: out REAL;
                               GOOD: out BOOLEAN);
procedure READ (L: inout LINE; VALUE: out REAL);

procedure READ (L: inout LINE; VALUE: out STRING;
                               GOOD: out BOOLEAN);
procedure READ (L: inout LINE; VALUE: out STRING);

procedure READ (L: inout LINE; VALUE: out TIME;
                               GOOD: out BOOLEAN);
procedure READ (L: inout LINE; VALUE: out TIME);

procedure SREAD (L: inout LINE; VALUE: out STRING;
                                STRLEN: out NATURAL);
alias STRING_READ is SREAD [LINE, STRING, NATURAL];

alias BREAD is READ [LINE, BIT_VECTOR, BOOLEAN];
alias BREAD is READ [LINE, BIT_VECTOR];
alias BINARY_READ is READ [LINE, BIT_VECTOR, BOOLEAN];
alias BINARY_READ is READ [LINE, BIT_VECTOR];

procedure OREAD (L: inout LINE; VALUE: out BIT_VECTOR;
                                GOOD: out BOOLEAN);
procedure OREAD (L: inout LINE; VALUE: out BIT_VECTOR);
alias OCTAL_READ is OREAD [LINE, BIT_VECTOR, BOOLEAN];
alias OCTAL_READ is OREAD [LINE, BIT_VECTOR];

procedure HREAD (L: inout LINE; VALUE: out BIT_VECTOR;
                                GOOD: out BOOLEAN);
procedure HREAD (L: inout LINE; VALUE: out BIT_VECTOR);
alias HEX_READ is HREAD [LINE, BIT_VECTOR, BOOLEAN];
alias HEX_READ is HREAD [LINE, BIT_VECTOR];
Щелкните здесь, чтобы просмотреть определения процедур ввода из библиотеки std_logic_1164
procedure READ (L : inout LINE; VALUE : out STD_ULOGIC; GOOD : out BOOLEAN);
procedure READ (L : inout LINE; VALUE : out STD_ULOGIC);

procedure READ (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR; GOOD : out BOOLEAN);
procedure READ (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR);

alias BREAD is READ [LINE, STD_ULOGIC_VECTOR, BOOLEAN];
alias BREAD is READ [LINE, STD_ULOGIC_VECTOR];
alias BINARY_READ is READ [LINE, STD_ULOGIC_VECTOR, BOOLEAN];
alias BINARY_READ is READ [LINE, STD_ULOGIC_VECTOR];

procedure OREAD (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR; GOOD : out BOOLEAN);
procedure OREAD (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR);
alias OCTAL_READ is OREAD [LINE, STD_ULOGIC_VECTOR, BOOLEAN];
alias OCTAL_READ is OREAD [LINE, STD_ULOGIC_VECTOR];

procedure HREAD (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR; GOOD : out BOOLEAN);
procedure HREAD (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR);
alias HEX_READ is HREAD [LINE, STD_ULOGIC_VECTOR, BOOLEAN];
alias HEX_READ is HREAD [LINE, STD_ULOGIC_VECTOR];

Читать шестнадцатеричные значения из файла

Шестнадцатеричный формат — это удобный формат для описания содержимого ОЗУ, потому что два шестнадцатеричных символа непосредственно преобразуются в один байт, восемь бит. Каждый символ описывает полубайт, а каждая строка в текстовом файле описывает содержимое одного слота оперативной памяти. В приведенном ниже листинге показана выдержка из файла ram_content_hex.txt. файл. Он заполнен примерами значений в диапазоне от 1 до 256 десятичных знаков, записанных в шестнадцатеричном формате.

12–255256 00000001 00000002 ... 000000FF 00000100

Для загрузки данных из текстового файла мы используем нечистую функцию, объявленную ниже ram_type. , но выше объявления сигнала RAM. Код ниже показывает init_ram_hex функция, которая считывает данные из текстового файла и возвращает их в виде ram_type объект.

impure function init_ram_hex return ram_type is
  file text_file : text open read_mode is "ram_content_hex.txt";
  variable text_line : line;
  variable ram_content : ram_type;
begin
  for i in 0 to ram_depth - 1 loop
    readline(text_file, text_line);
    hread(text_line, ram_content(i));
  end loop;

  return ram_content;
end function;

readline Процедура внутри цикла for считывает за раз одну строку текста и присваивает ее text_line переменная. Этот объект имеет тип line , который является типом доступа к строковому объекту, указателю на динамически выделяемую строку. На следующей строке hread процедура читает строку из line объект и преобразует его в std_ulogic_vector . Этот тип может быть назначен непосредственно на std_logic_vector из которых состоит каждая ячейка ОЗУ.

Наконец, мы объявляем сигнал RAM при вызове нашего init_ram_hex. функция для предоставления начальных значений для него:

signal ram_hex : ram_type := init_ram_hex;

HREAD в VHDL-2002 и VHDL-93

К сожалению, HREAD процедура доступна только в VHDL-2008. Во всех предыдущих версиях VHDL стандартный READ вместо этого следует использовать процедуру. READ процедура перегружена множеством различных типов вывода, но нет возможности чтения шестнадцатеричных значений.

Давайте напишем собственный алгоритм для преобразования шестнадцатеричных символов ASCII в VHDL std_logic_vector. . Во-первых, нам нужно прочитать символы один за другим из text_line объект, затем мы декодируем их значения и присваиваем их правильному фрагменту вектора слота RAM. В приведенном ниже коде показана эквивалентная реализация init_ram_hex функция, которая также работает в устаревших версиях VHDL.

impure function init_ram_hex return ram_type is
  file text_file : text open read_mode is "ram_content_hex.txt";
  variable text_line : line;
  variable ram_content : ram_type;
  variable c : character;
  variable offset : integer;
  variable hex_val : std_logic_vector(3 downto 0);
begin
  for i in 0 to ram_depth - 1 loop
    readline(text_file, text_line);

    offset := 0;

    while offset < ram_content(i)'high loop
      read(text_line, c);

      case c is
        when '0' => hex_val := "0000";
        when '1' => hex_val := "0001";
        when '2' => hex_val := "0010";
        when '3' => hex_val := "0011";
        when '4' => hex_val := "0100";
        when '5' => hex_val := "0101";
        when '6' => hex_val := "0110";
        when '7' => hex_val := "0111";
        when '8' => hex_val := "1000";
        when '9' => hex_val := "1001";
        when 'A' | 'a' => hex_val := "1010";
        when 'B' | 'b' => hex_val := "1011";
        when 'C' | 'c' => hex_val := "1100";
        when 'D' | 'd' => hex_val := "1101";
        when 'E' | 'e' => hex_val := "1110";
        when 'F' | 'f' => hex_val := "1111";

        when others =>
          hex_val := "XXXX";
          assert false report "Found non-hex character '" & c & "'";
      end case;

      ram_content(i)(ram_content(i)'high - offset
        downto ram_content(i)'high - offset - 3) := hex_val;
      offset := offset + 4;

    end loop;
  end loop;

  return ram_content;
end function;

Алгоритм просто проходит через каждую строку, просматривая каждый символ, преобразуя его в правильное двоичное значение. Если встречается символ, не входящий в диапазон 0x0-0xF, в коде when others возникает ошибка подтверждения. ответвляться. offset переменная управляет положением среза в каждой ячейке памяти, которому присваивается декодированное значение.

Вы можете задаться вопросом, почему бы нам не создать собственный код hread. процедура вместо того, чтобы кодировать ее внутри init_ram_hex функция? Тогда нам не пришлось бы менять init_ram_hex функции вообще, мы просто использовали бы наш пользовательский hread процедура вместо отсутствующей стандартной.

Это будет работать в большинстве симуляторов и некоторых синтезаторах, таких как Lattice iCEcube2, но не будет работать в Xilinx Vivado. В приведенном ниже сообщении об ошибке четко указано, в чем проблема.

В Вивадо:
[Synth 8-27] Аргумент процедуры типа «строка» не поддерживается [init_ram_tb.vhd:15]

Нажмите здесь, чтобы увидеть альтернативную реализацию процедуры HREAD
procedure hread(l: inout line; value: out std_logic_vector) is
  variable c : character;
  variable ok : boolean;
  variable i : integer := 0;
  variable hex_val : std_logic_vector(3 downto 0);
begin
  while i < value'high loop
    read(l, c);
  
    case c is
      when '0' => hex_val := "0000";
      when '1' => hex_val := "0001";
      when '2' => hex_val := "0010";
      when '3' => hex_val := "0011";
      when '4' => hex_val := "0100";
      when '5' => hex_val := "0101";
      when '6' => hex_val := "0110";
      when '7' => hex_val := "0111";
      when '8' => hex_val := "1000";
      when '9' => hex_val := "1001";
      when 'A' | 'a' => hex_val := "1010";
      when 'B' | 'b' => hex_val := "1011";
      when 'C' | 'c' => hex_val := "1100";
      when 'D' | 'd' => hex_val := "1101";
      when 'E' | 'e' => hex_val := "1110";
      when 'F' | 'f' => hex_val := "1111";
  
      when others =>
        hex_val := "XXXX";
        assert false report "Found non-hex character '" & c & "'";
    end case;
  
    value(value'high - i downto value'high - i - 3) := hex_val;
    i := i + 4;
  end loop;
end procedure;

Чтение двоичных значений из файла

Вы можете сохранить значения ОЗУ в виде двоичных литералов вместо шестнадцатеричных символов, если ширина ОЗУ не кратна 8. В приведенном ниже листинге показано то же содержимое, что и раньше, но представленное в двоичном формате с использованием только символов 0 и 1 .

12–255256 00000000000000000000000000000001 00000000000000000000000000000010 ... 00000000000000000000000011111111 00000000000000000000000100000000

Алгоритм, показанный ниже, предназначен для чтения двоичных значений из файла. Это похоже на чтение шестнадцатеричных чисел, но в VHDL-2008 вы должны использовать BREAD вызов процедуры вместо HREAD . Он преобразует один символ ASCII в один std_ulogic. значение, которое неявно преобразуется в std_logic .

impure function init_ram_bin return ram_type is
  file text_file : text open read_mode is "ram_content_bin.txt";
  variable text_line : line;
  variable ram_content : ram_type;
begin
  for i in 0 to ram_depth - 1 loop
    readline(text_file, text_line);
    bread(text_line, ram_content(i));
  end loop;

  return ram_content;
end function;

Наконец, мы инициализируем сигнал RAM, вызвав нашу новую нечистую функцию, как показано в коде ниже.

signal ram_bin : ram_type := init_ram_bin;

ХЛЕБ в VHDL-2002 и VHDL-93

Мы можем легко сделать наш код переносимым на устаревшие версии VHDL, вызвав READ вместо BREAD . Выдержка из стандарта VHDL ниже показывает прототип READ. которые мы заинтересованы в использовании.

procedure READ (L: inout LINE; VALUE: out BIT);

READ процедура, которая выводит std_ulogic не существовало до VHDL-2008, поэтому мы должны использовать bit версия из TEXTIO библиотека. К счастью, этот тип можно легко преобразовать в std_logic. с помощью стандартного To_StdLogicVector функция.

Реализация init_ram_bin показанный ниже работает в VHDL-2002, а также в VHDL-93.

impure function init_ram_bin return ram_type is
  file text_file : text open read_mode is "ram_content_bin.txt";
  variable text_line : line;
  variable ram_content : ram_type;
  variable bv : bit_vector(ram_content(0)'range);
begin
  for i in 0 to ram_depth - 1 loop
    readline(text_file, text_line);
    read(text_line, bv);
    ram_content(i) := To_StdLogicVector(bv);
  end loop;

  return ram_content;
end function;

Бэкпорт библиотеки IEEE std_logic_1164

Альтернативой изменению кода для устаревших версий VHDL является использование стороннего пакета std_logic_1164_additions. Загрузив и добавив эту библиотеку в свой проект, вы сможете использовать новые процедуры также в VHDL-2002 и VHDL-93. Конечно, тогда вы будете импортировать намного больше, и ваш код всегда будет зависеть от этого пакета.


VHDL

  1. Как защитить алюминий от коррозии
  2. Чем металлические элементы отличаются от неметаллических элементов
  3. Как создать шаблон CloudFormation с помощью AWS
  4. Чем облачные вычисления отличаются от традиционных вычислений?
  5. Как писать комментарии в программировании на C
  6. Java BufferedReader:как читать файл в Java с примером
  7. Среднее значение Python:как найти СРЕДНЕЕ значение списка в Python
  8. Что такое Микрометр? | Как вы читаете микрометр
  9. Как вызвать функциональный блок из клиента OPC UA с помощью информационной модели
  10. Как читать чертежи ЧПУ