Инициализация блочной памяти FPGA из текстовых файлов с помощью библиотеки TEXTIO в VHDL
Наполнение блочной памяти предопределенными значениями наиболее эффективно делается чтением бинарных или шестнадцатеричных литералов из ASCII-файла. Эта техника также служит для создания ROM, так как FPGA ROM — это просто RAM, из которого только читают.
Для примеров ниже в декларативной области VHDL-файла объявлены следующие константы и тип RAM:
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
Чтение строк и данных с TEXTIO
Пакет TEXTIO, находящийся в стандартной библиотеке std, предоставляет подпрограммы, необходимые для файлового ввода-вывода. Он автоматически доступен, нужно только импортировать его:
use std.textio.all;
Наши данные RAM будут храниться в ASCII-файле, где каждая строка представляет одно слово памяти. Процедура READLINE читает одну строку в объект LINE. Её прототип:
procedure READLINE (file F: TEXT; L: inout LINE); type LINE is access STRING; -- указатель на динамически выделенную строку
VHDL‑2008 вводит OREAD, HREAD и BREAD для извлечения восьмеричных, шестнадцатеричных и двоичных значений из объекта LINE. Для краткости сфокусируемся на чтении шестнадцатеричных и двоичных значений. Соответствующие объявления:
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];
Для старых версий VHDL (до 2008) должна использоваться стандартная процедура READ, которая не поддерживает шестнадцатеричный формат напрямую. В этом случае требуется собственная рутина конвертации.
Загрузка шестнадцатеричных данных
Шестнадцатеричная нотация удобна, потому что каждая пара шестнадцатеричных цифр напрямую отображается в байт. Пример файла ram_content_hex.txt содержит 256 строк, каждая с 8-символьной шестнадцатеричной строкой от 00000001 до 00000100:
| 1 2 … 255 256 | 0000000100000002…000000FF00000100 |
Следующая нечистая функция читает файл и возвращает полностью инициализированный массив ram_type. Она работает с VHDL‑2008 и новее:
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;
После определения функции сигнал RAM инстанцируется с начальным содержимым:
signal ram_hex : ram_type := init_ram_hex;
Устаревший VHDL: ручная реализация HREAD
Когда HREAD недоступен (например, VHDL‑93 или VHDL‑2002), рутину ручной конвертации можно встроить в функцию инициализации. Следующий пример демонстрирует этот подход:
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;
Хотя можно определить выделенную процедуру HREAD, большинство инструментов синтеза (например, Xilinx Vivado) не поддерживают процедуры, принимающие аргумент типа LINE. Следующая ошибка иллюстрирует это ограничение:
В Vivado:
[Synth 8-27] Procedure argument of type ‘line’ is not supported [init_ram_tb.vhd:15]
Чтение двоичных данных
Если ширина RAM не кратна 8, двоичные литералы могут быть предпочтительнее. Пример файла ram_content_bin.txt содержит 256 строк, каждая с 32-битной двоичной строкой:
| 1 2 … 255 256 | 0000000000000000000000000000000100000000000000000000000000000010…0000000000000000000000001111111100000000000000000000000100000000 |
В VHDL‑2008 процедура BREAD может использоваться для прямого чтения двоичных значений:
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: двоичное чтение с READ
Для VHDL‑2002 или VHDL‑93 должна использоваться процедура READ. Поскольку она возвращает вектор bit, результат конвертируется в std_logic_vector через To_StdLogicVector:
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;
Перенос современных возможностей TEXTIO
Если вы предпочитаете не менять устаревший код, можно импортировать сторонний пакет std_logic_1164_additions. Эта библиотека переносит процедуры HREAD и BREAD на старые версии VHDL ценой дополнительной зависимости.
Для более детальных примеров и дальнейшего чтения см. сопровождающие статьи в этой серии.
VHDL
- Защита алюминия от коррозии: экспертные стратегии для долговечности
- Металлы против неметаллов: ключевые различия объяснены
- Создайте свой первый шаблон AWS CloudFormation — практическое руководство
- Облачные вычисления против традиционных: практическое сравнение
- Комментарии в C: пишем понятные и эффективные заметки
- Чтение файлов в Java с BufferedReader — Практическое руководство с примерами
- Вычисление среднего значения в Python: практическое руководство
- Микрометр: как читать и использовать этот точное измерительный инструмент
- Вызов функциональных блоков ПЛК через OPC UA клиентов: Практическое руководство
- Освоение чтения чертежей для ЧПУ: ключевые навыки современного машиниста