Как инициализировать 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]
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
- Как защитить алюминий от коррозии
- Чем металлические элементы отличаются от неметаллических элементов
- Как создать шаблон CloudFormation с помощью AWS
- Чем облачные вычисления отличаются от традиционных вычислений?
- Как писать комментарии в программировании на C
- Java BufferedReader:как читать файл в Java с примером
- Среднее значение Python:как найти СРЕДНЕЕ значение списка в Python
- Что такое Микрометр? | Как вы читаете микрометр
- Как вызвать функциональный блок из клиента OPC UA с помощью информационной модели
- Как читать чертежи ЧПУ