Волею судьбы занят сейчас программированием ПЛИС компании Altera семейства Cyclone IV. А тут, как известно, рано или поздно встает вопрос о моделировании.
Вы возможно скажете: «Ну так бери ModelSim и моделируй». Только одна проблема! Я ленивый…
Мне нужно промоделировать блок у которого на вход приходит адрес (16 битное число) и сигнал CS, а на выход он выплевывает кучу разнообразных сигналов управления.
Но в данном контексте это не важно.
Важно то, что мне нужно перебрать кучу значений адреса, что довольно трудозатратно.
Но не беда! Просто сделаем так, чтобы ModelSim брал данные для симуляции из такого файла:
#cs addr 1 0 0 0 0 1 0 2 0 3 ....
Исследуемый блок выглядит так:
entity cs_mux is
port ( addr : in integer range 0 to 2047;
cs : in bit;
sys_control : out bit;
sync : out bit;
data_collector : out bit;
async_ports : out bit_vector(11 downto 0);
recv_buffers : out bit_vector(11 downto 0);
transiver_buffers : out bit_vector(11 downto 0)
);
end cs_mux;
Начнем делать наш Testbench.
Объявим пустой entity и библиотеки.
library IEEE; use IEEE.numeric_std.all; use STD.TEXTIO.all; --package with routines for reading/writing files entity TEST_MUX is end entity;
Приступим к архитектуре. Тут нужно обявить по сигналу для каждого входа/выхода и компонент.
architecture RTL of TEST_MUX is
signal cs : bit;
signal addr : integer range 0 to 2047;
signal sys_control : bit;
signal sync : bit;
signal data_collector : bit;
signal async_ports : bit_vector(11 downto 0);
signal recv_buffers : bit_vector(11 downto 0);
signal transiver_buffers : bit_vector(11 downto 0);
file infile : text is in "mux_file.txt"; --файл с исходными данными
component cs_mux
port ( addr : in integer range 0 to 2047;
cs : in bit;
sys_control : out bit;
sync : out bit;
data_collector : out bit;
async_ports : out bit_vector(11 downto 0);
recv_buffers : out bit_vector(11 downto 0);
transiver_buffers : out bit_vector(11 downto 0)
);
end component;
begin
Тут главное не пропустить декларацию файла.
Дальше создаем схему.
U1: cs_mux
port map(
addr => addr,
cs => cs,
sys_control => sys_control,
sync => sync,
data_collector => data_collector,
async_ports => async_ports,
recv_buffers => recv_buffers,
transiver_buffers => transiver_buffers
);
Тут тоже все просто. Соединяем наши сигналы со входами/выходами компонента.
А теперь вся магия.
Процесс загрузки данных из файла.
process
variable s : line;
variable gooda, goodc : Boolean;
variable addrv : integer range 0 to 2047;
variable csv : bit;
begin
if endfile(infile) then
wait;
end if;
readline(infile,s);
if s(s'low) /= '#' then
read(s, csv, goodc);
read(s, addrv, gooda);
if gooda and goodc then
addr <= addrv;
cs <= csv;
wait for 10ns;
else
wait;
end if;
end if;
end process;
Тут мы построчно читаем файл. В каждой строке пропускаем все после диеза (это у нас символ комментария такой).
Дальше при помощи функции read читаем сигналы из строки. И если все хорошо (goodc и gooda в значении 1), то присваиваем считанные значения сигналам. После каждой такой процедуры ждем 10нс.
В итоге получается нечто подобное:

А я довольный попиваю кофе 😉




