Создание делителя частоты в 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;
Другие вопросы по тегам