VHDL testbench для устройства, которое использует два ранее определенных и проверенных объекта
Предупреждение: это будет долго. Извините, если это слишком многословно.
Я только начинаю изучать FPGA и VHDL, используя Quartus Prime. За последние несколько дней я научил себя:
- Как написать VHDL
- Как сделать компонент
- Как написать тестовый стенд
- Как использовать ранее созданные и протестированные компоненты - связанные вместе - для создания нового компонента
Однако я не могу понять, как создать тестовый стенд, который тестирует новый компонент, использующий два существующих компонента, когда некоторые сигналы, содержащиеся в этом новом компоненте, являются только внутренними сигналами.
Итак, вот два сверхпростых компонента, которые я успешно написал и протестировал на испытательных стендах. Между прочим, я понимаю, что это не настоящий мир, я просто пытаюсь сделать маленькие шаги.
1. Четырехбитный регистр
library ieee;
use ieee.std_logic_1164.all;
entity four_bit_reg is
port
(
bcd_in: in std_logic_vector(3 downto 0);
clk: in std_logic;
clr: in std_logic;
bcd_out: out std_logic_vector(3 downto 0)
);
end four_bit_reg;
architecture behaviour of four_bit_reg is
begin
process (clk,clr)
begin
if (clr = '1') then
bcd_out <= "0000";
elsif rising_edge(clk) then
bcd_out <= bcd_in;
end if;
end process;
end behaviour;
2. Преобразователь BCD в семь сегментов
library ieee;
use ieee.std_logic_1164.all;
entity sev_seg is
port
(
bcd_value : in std_logic_vector(3 downto 0);
sev_seg_value : out std_logic_vector(6 downto 0)
);
end sev_seg;
architecture behaviour of sev_seg is
begin
sev_seg_process : process (bcd_value)
begin
case bcd_value is
when "0000" => sev_seg_value <="0111111"; -- 0
when "0001" => sev_seg_value <="0000110"; -- 1
when "0010" => sev_seg_value <="0111011"; -- 2
when "0011" => sev_seg_value <="1001111"; -- 3
when "0100" => sev_seg_value <="1100110"; -- 4
when "0101" => sev_seg_value <="1101101"; -- 5
when "0110" => sev_seg_value <="1111101"; -- 6
when "0111" => sev_seg_value <="0000111"; -- 7
when "1000" => sev_seg_value <="1111111"; -- 8
when "1001" => sev_seg_value <="1101111"; -- 9
when others => sev_seg_value <= "0000000"; -- A to F should show blank
end case;
end process sev_seg_process;
end behaviour;
Первый вопрос: что вы называете двумя вещами выше? Компоненты? Модули? Сущности? Что-то другое?
Затем я использую эти два в другом новом компоненте / объекте / модуле (в зависимости от обстоятельств), как показано ниже:
library ieee;
use ieee.std_logic_1164.all;
entity two_modules is
port
(
bcd_pins : in std_logic_vector(3 downto 0);
sev_seg_pins : out std_logic_vector(6 downto 0)
);
end two_modules;
architecture behaviour of two_modules is
-- Internal signals
signal int_clk: std_logic;
signal int_bus: std_logic_vector(3 downto 0);
-- List any components used in the design
component four_bit_reg is
port
(
bcd_in: in std_logic_vector(3 downto 0);
clk: in std_logic;
clr: in std_logic;
bcd_out: out std_logic_vector(3 downto 0)
);
end component;
component sev_seg is
port
(
bcd_value : in std_logic_vector(3 downto 0);
sev_seg_value : out std_logic_vector(6 downto 0)
);
end component;
begin -- start the instances
fbr: four_bit_reg port map
(
clk => int_clk,
bcd_in => bcd_pins,
clr => '0',
bcd_out => int_bus
);
sseg: sev_seg port map
(
bcd_value => int_bus,
sev_seg_value => sev_seg_pins
);
end behaviour;
Итак, для этой вещи, которую я назвал two_modules, структура для тестового стенда, созданная Quartus, выглядит следующим образом:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY two_modules_vhd_tst IS
END two_modules_vhd_tst;
ARCHITECTURE two_modules_arch OF two_modules_vhd_tst IS
-- constants
-- signals
SIGNAL bcd_pins : STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL sev_seg_pins : STD_LOGIC_VECTOR(6 DOWNTO 0);
signal internal_clock : std_logic := '0';
COMPONENT two_modules
PORT (
bcd_pins : IN STD_LOGIC_VECTOR(3 DOWNTO 0);
sev_seg_pins : OUT STD_LOGIC_VECTOR(6 DOWNTO 0)
);
END COMPONENT;
BEGIN
i1 : two_modules
PORT MAP (
-- list connections between master ports and signals
bcd_pins => bcd_pins,
sev_seg_pins => sev_seg_pins
);
internal_clock <= not internal_clock after 500 us;
init : PROCESS
-- variable declarations
BEGIN
-- code that executes only once
WAIT;
END PROCESS init;
always : PROCESS
-- optional sensitivity list
-- ( )
-- variable declarations
BEGIN
-- code executes for every event on sensitivity list
WAIT;
END PROCESS always;
END two_modules_arch;
Как вы можете видеть, я создал внутренние часы, и я хотел бы, просто для того, чтобы научиться делать подобные вещи, подчеркиваю, я понимаю, что это не полный дизайн, присоединяйтесь к internal_clock (который я вижу, работает и представляет собой сигнал в редакторе сигналов модели Sim), чтобы кликнуть в four_bit_reg.
Я думаю и надеюсь, что когда я знаю, как это сделать, я смогу вспахать и получить настоящий сложный испытательный стенд. Однако после долгих поисков я не могу найти ссылки на то, как связать воедино сигналы от подкомпонентов. Это может быть потому, что я использую совершенно неправильную терминологию и где-то там может быть идеальное руководство.
Так:
- Как я могу просто для начала подключить мой internal_clock к подкомпоненту, входу clk four_bit_reg?
- Какова правильная терминология, когда вы используете и соединяете такие вещи, как four_bit_reg и sev_seg? Подкомпоненты? Что-то другое?
Большое спасибо, если вы получили это далеко!
3 ответа
С комментариями я понимаю, что вы используете внутренний генератор от Altera в вашем CPLD.
Я предлагаю добавить третий модуль с именем "internal_oscillator", который можно описать следующим образом:
library ieee;
use ieee.std_logic_1164.all;
entity internal_oscillator is
port (
CLK : out std_logic
);
end entity;
architecture for_simulation_only of internal_oscillator is
constant C_HALF_PERIOD : time := 5 ns; -- 100MHz
signal clk_internal : std_logic := '0';
begin
clk_internal <= not clk_internal after C_HALF_PERIOD;
CLK <= clk_internal;
end architecture;
Теперь вы можете добавить этот модуль в свой дизайн, и вы получите часы, не добавляя новый пин-код на объекте верхнего уровня:
osc_inst : entity work.internal_oscillator
port map (CLK => int_clk);
В большинстве случаев часы являются входом для модуля. Часто сопровождается сбросом.
Если вы посмотрите на WWW, например, код VHDL, вы заметите, что у каждого модуля есть вход часов.
Есть два основных исключения:
- Испытательные стенды генерируют искусственные часы внутри, чтобы управлять проверяемым устройством.
- Модули, которые имитируют реальную тактовую генерацию, например, кварцевый генератор.
В вашем two_models
объект, добавьте новый порт для тактового сигнала:
entity two_modules is
port
(
clk : in std_logic;
bcd_pins : in std_logic_vector(3 downto 0);
sev_seg_pins : out std_logic_vector(6 downto 0)
);
end two_modules;
Удалить int_clk
сигнал в two_models
архитектура. Замените его ранее определенным входным сигналом, когда вы подключаете подмодули:
fbr: four_bit_reg port map
(
clk => clk_in,
bcd_in => bcd_pins,
clr => '0',
bcd_out => int_bus
);
В вашем тестовом стенде подключите внутренний тактовый сигнал internal_clock
в этот порт two_modules
:
PORT MAP (
-- list connections between master ports and signals
clk_in => internal_clock,
bcd_pins => bcd_pins,
sev_seg_pins => sev_seg_pins
);