Создание делителя частоты в VHDL
ОСНОВНЫЕ РЕДАКТИРОВАТЬ:
Проблема была решена после прочтения комментария Уилла Дина. Оригинальный вопрос ниже пересмотренного кода:
-- REVISED CODE (NOW WORKS)
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
entity CLOCK_DIVIDER is
port(
reset : in std_logic;
clk : in std_logic;
half_clk : out std_logic
);
end CLOCK_DIVIDER;
architecture CLOCK_DIVIDER of CLOCK_DIVIDER is
signal tick : std_logic;
begin
process(clk, reset)
begin
if reset = '1' then
tick <= '0';
elsif clk = '1' and clk'EVENT then
if tick = '0' then
tick <= '1';
elsif tick = '1' then
tick <= '0';
end if;
end if;
end process;
process(tick)
begin
half_clk <= tick;
end process
end CLOCK_DIVIDER;
Синтезированный логический блок пересмотренного кода представляет собой одиночный DFF с асинхронным сбросом, который принимает half_clk в качестве вывода и инвертированный half_clk в качестве ввода, что означает, что значение half_clk изменяется на каждом переднем фронте clk.
Спасибо, Уилл Дин:)
==== ==== ==== ==== ====
Оригинальный вопрос ниже:
==== ==== ==== ==== ====
Мне нужен простой делитель часов (просто делим на два), и вместо того, чтобы использовать шаблон, я подумал, что попытаюсь написать его сам, чтобы продолжать обучение.
К сожалению, синтезированный логический блок не работает - я представляю логический блок и код (который, я думаю, должен работать) в указанном порядке.
http://img808.imageshack.us/img808/3333/unledly.png
Что мне действительно интересно, так это то, что у дьявола с "тиковым" DFF - он, очевидно, берет свой вклад от селектора мультиплексора, который... Да.
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
entity CLOCK_DIVIDER is
port(
reset : in std_logic;
clk : in std_logic;
half_clk : out std_logic
);
end CLOCK_DIVIDER;
architecture CLOCK_DIVIDER of CLOCK_DIVIDER is
signal tick : std_logic;
begin
process(clk, reset)
begin
if reset = '1' then
half_clk <= '0';
tick <= '0';
elsif clk = '1' and clk'EVENT then
if tick = '0' then
half_clk <= '0';
tick <= '1';
elsif tick = '1' then
half_clk <= '1';
tick <= '0';
end if;
end if;
end process;
end CLOCK_DIVIDER;
Я уверен, что ошибка в коде очевидна, но я слепо пытался ее найти.
4 ответа
Исходя из вашего пересмотренного кода, я предлагаю эту модификацию архитектуры:
-- REVISED CODE (NOW WORKS) and simplified and synthesisable
architecture CLOCK_DIVIDER of CLOCK_DIVIDER is
signal tick : std_logic;
begin
process(clk, reset)
begin
if reset = '1' then
tick <= '0';
elsif rising_edge(clk) then -- use of rising_edge() is the correct idiom these days
tick <= not tick;
end if;
end process;
half_clk <= tick;
end CLOCK_DIVIDER;
Я удалил этот процесс и заменил параллельным назначением:
process(tick)
begin
half_clk <= tick;
end process
как то, что это просит, это триггер с двумя краями tick
,
Похоже, это достигнет того, что вы хотите, с точки зрения того, что формы сигналов покачиваются так, как вы хотите, но не синтезируют. Это также добавляет дополнительную дельта-задержку к выходу, которая может вызвать или не вызвать проблемы, если вы используете ее как часы "в будущем". Как прокомментировали другие, в большинстве архитектур это не очень хороший план (но для некоторых это "правильный путь").
Если Halfclk должен использоваться в качестве разрешения, а не настоящих часов, не обращайте внимания на этот совет...
Если это для цели FPGA, а "half_clk" действительно используется в качестве часов (например, идет к выводу синхронизации на DFF, а не к выводу включения)... Не делайте этого.
Создание производных часов с использованием общей логики /fabic ПЛИС приведет к проблемам с инструментами сборки и может в конечном итоге привести к сбоям сборок (не будет соответствовать времени) или сборкам, которые ведут себя не так, как ожидалось, поскольку ограничения не были правильно переданы во все сети синхронизации,
Вместо этого используйте блоки управления часами, которые встроены в матрицу ПЛИС специально для этой цели. В мире запчастей Xilinx их называют цифровыми часовыми менеджерами (DCM) или смешанными режимами часовых менеджеров (MMCM). Я не уверен, что эквивалентный компонент Altera. Прочитайте документацию, чтобы определить наилучшее использование для вашего приложения.
Вы уверены, что сбрасываете при запуске? То, как вы определили условие для тика, ничего не произойдет, если тик не равен нулю или единице (то есть: это могут быть U, Z, X и т. Д.).
Я обычно предлагаю покрывать все случаи с вашими условными выражениями, то есть:
if tick = '0' then
half_clk <= '0';
tick <= '1';
else
half_clk <= '1';
tick <= '0';
end if;
или же
if tick = '0' then
half_clk <= '0';
tick <= '1';
elsif tick = '1' then
half_clk <= '1';
tick <= '0';
else
-- Throw error or something here
end if;
Простой счетчик делает свое дело (правильный путь, конечно, DCM):
signal cnt : std_logic_vector(3 downto 0);
...
clk_div_2 <= cnt(0);
clk_div_4 <= cnt(1);
clk_div_8 <= cnt(2);
clk_div_16 <= cnt(3);
...
process(clk)
if clk'event and clk = '1' then
cnt <= cnt + 1;
end if;
end process;