2016-03-22 3 views
4

У меня есть следующий упрощенный пример моего кода, в котором объект модели DeltasTest можно моделировать, чтобы показать проблему. Часы реального дизайна инвертированы или не основаны на общем значении и подают несколько других объектов ниже этого.Как решить эту проблему с задержкой тактового цикла Delta

Проблема в том, что простой детектор края не работает (data_out - это просто сбой) в поведенческом моделировании из-за задержки цикла дельта, введенной на часах на этапе инверсии. Есть ли стандартный или иначе элегантный способ решить эту проблему?

До сих пор мое лучшее решение - назначить сигнал data_in другому сигналу, чтобы дать ему такую ​​же задержку цикла дельта, как clk. Я подумал о том, чтобы использовать функцию для инвертирования часов по мере необходимости на основе общего параметра в качестве второго параметра функции, но часы используются во многих местах, и это не показалось нам очень изящным, и я заметил, что он даже решит проблему проблема. Прижимаясь к соломинкам, я также попытался сделать назначение инверсии тактового сигнала transport, но, как и ожидалось, это не имело никакого значения.

library IEEE; 
use IEEE.STD_LOGIC_1164.ALL; 

entity Deltas is 
    Generic (
     CLK_INVERT : boolean := false 
    ); 
    Port (
     clk : in std_logic; 
     data_in : in std_logic 
    ); 
end Deltas; 

architecture Behavioral of Deltas is 

    -- Signals 
    signal data_reg : std_logic := '0'; 
    signal clk_inverted : std_logic := '0'; 
    signal data_out : std_logic := '0'; 

begin 

    ClkInvert : if (CLK_INVERT) generate 
     clk_inverted <= not clk; 
    else generate 
     clk_inverted <= clk; 
    end generate; 

    process (clk_inverted) 
    begin 
     if (rising_edge(clk_inverted)) then 
      data_reg <= data_in; 
     end if; 
    end process; 

    process (data_reg, data_in) 
    begin 
     if (data_reg /= data_in) then 
      data_out <= '1'; 
     else 
      data_out <= '0'; 
     end if; 
    end process; 

    -- Other entities use `clk_inverted`. Commented out so that this example compiles 
    --LowerEntity : entity work.Counter 
    --port map (
    -- clk => clk_inverted 
    --); 

end Behavioral; 

library IEEE; 
use IEEE.STD_LOGIC_1164.ALL; 

entity DeltasTest is 
end DeltasTest; 

architecture Behavioral of DeltasTest is 

    signal clk : std_logic := '0'; 
    signal data_in : std_logic := '0'; 

begin 

    clk <= not clk after 10 ns; 

    process (clk) 
     variable count : integer := 0; 
    begin 
     if (rising_edge(clk)) then 
      count := count + 1; 
      if (count = 4) then 
       count := 0; 
       data_in <= not data_in; 
      end if; 
     end if; 
    end process; 

    uut : entity work.Deltas 
    Port map (
     clk => clk, 
     data_in => data_in 
    ); 

end Behavioral; 
+0

Два вопроса: 1) Почему в 'Deltas'' '' '' '' '_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ вместо того, чтобы генерировать' clk_inverted' с дельта-задержкой, а затем использовать 'rising_edge()' на этом? 2) Почему не генерируются стимулы на 'data_in', созданные на основе' clk', как это было бы в реальном дизайне, а не только на основе времени? Изменение этого приведет к тому, что краевой детектор будет работать. Если требуется инвертированные часы, сделайте это на уровне, отличном от clk, и распределите по иерархии. –

+2

@MortenZilmer Спасибо за комментарии. 1) Я не использую 'fall_edge()', потому что полярность часов зависит от общего. 2) Сигнал данных фактически генерируется 'clk', но это в конечном счете не имеет никакого значения, поскольку мой пример не был точно таким же, как мой реальный код. Я обновлю пример, чтобы включить ваши изменения. –

+0

Вы можете найти более широкую аудиторию по адресу http://electronics.stackexchange.com/ – Tansir1

ответ

3

Я думаю, что ваше «решение» дополнительного дельта цикла на data_in, вероятно, чистейший простое решение.

Семантически назначение clk_inverted может перевести на аппаратное обеспечение в качестве преобразователя в тактовый сигнал, поэтому задержка дельта-цикла в моделировании представляет собой (возможно (*) реальное) состояние гонки, введенное в реальном оборудовании.

Таким образом, поведение моделирования - это не просто раздражение, но и полезное свойство, предупреждающее вас о потенциальном отклонении от хорошей синхронной практики проектирования, к которой необходимо прислушаться.

(*) Только «возможно реальный», потому что, в зависимости от технологии, синтез может «подталкивать» инверсию в нижестоящий FF, вместо этого обнаруживая противоположный край - автоматически преобразуя ваш дизайн в комментарий Мортена.

Это становится более сложной задачей, когда дополнительный дельта-цикл похож на чужой IP-адрес, возможно, на модель внешнего компонента, такого как память. Затем IP-адрес больше не находится под вашим контролем, и имитация уровня платы может считывать или записывать данные в неправильный такт.

Здесь я хочу добавить приблизительные задержки ввода-вывода как инерционные задержки в назначениях ввода-вывода FPGA (из таблицы данных FPGA или синтетического отчета) или в качестве задержек переноса на печатной плате. Это гарантирует, что мои симуляции приближаются к поведению платы - не совсем, но достаточно близко, чтобы позволить мне спроектировать внутреннюю логику после обычной синхронной практики.


Чистое решение должно состоять в том, чтобы генерировать два разных тактовых процесса на основе общего. Это полностью исключает сложный дельта-цикл.

FINALLY! применение для 2-процесса формы СМ, где, сохраняя отсчитанные процессы как можно более простым имеет преимущество ...

не так быстро ...

поведение вы хотите, чтобы реорганизовать обнаружение фронта тактового импульса , который уже реорганизуется в простую функцию из устаревшего и сложного (уровня и события) выражения.

Почему бы не рефакторировать обнаружение края часов дальше, например ...

function clock_edge(signal clk : in std_logic) return boolean is 
begin 
    if CLK_INVERT then 
     return falling_edge(clk); 
    else 
     return rising_edge(clk); 
    end if; 
end clock_edge; 
... 

process (my_clock) is 
begin 
    if clock_edge(my_clk) then ... 

Я не тестировал это, чтобы убедиться, что инструменты синтеза могут реализовать это по желанию. Вероятно, некоторые из них, возможно, не будут (если они просто специально оперируют системными функциями вместо того, чтобы выполнять работу должным образом)

В иерархическом дизайне эта функция была бы в пакете, который использовался бы любыми объектами, которые в нем нуждались , Это создает проблемы видимости родового: одно предположение заключалось бы в использовании константы в пакете, а другой - передать общий параметр в качестве второго параметра функции. Правильный подход, вероятно, зависит от ограничений, налагаемых инструментом синтеза.

+0

Спасибо за ответ. Собственный сигнал данных фактически создается внутри FPGA таким же образом, как показано в моем обновленном стенде выше в этом конкретном проекте, но рассматриваемый объект может использоваться в сценарии, где оба сигнала являются внешними входами. Интересно, что это может быть проблемой реального мира, если был вставлен фактический инвертор. –

+0

Другим решением было бы генерировать два разных тактовых процесса на основе общего. В КОНЦЕ КОНЦОВ! использование для 2-технологической формы SM, где сохранение тактовых процессов как можно более простое имеет преимущество! –

+0

Спасибо за дополнительные идеи, я не думал о том, что функция краевых функций часов является «локальной» функцией, которая тогда не должна быть передана логической каждый раз, что делает ее намного более чистым, чем если бы это было сделано как я думал. Основная проблема, хотя с использованием функции в этом случае заключается в том, что у этого объекта есть другие сущности, расположенные ниже, которые также используют инвертированные (или нет) часы. –

0

Я думаю, что у вас есть случай метастабильности. вы вводите данные, если они поступают из внешнего мира, возможно, не синхронизированы.

Clock data_in через два каскадных регистра и провести сравнение между двумя регистрами вместо сравнения data_reg с входным сигналом.

Я уверен, что я сделал эту ошибку, прежде чем

1

Как об использовании старого стиля часов и замене CLK_INVERT с CLK_POLARITY. Не сделал это сам, но я уверен, что видел его где-то.

entity Deltas is 
    Generic (
     CLK_POLARITY : std_logic := '1' 
    ); 
    Port (
     clk : in std_logic; 
     data_in : in std_logic 
    ); 
end Deltas; 
architecture Behavioral of Deltas is 
    signal data_reg : std_logic; 
    signal data_out : std_logic; 

begin 

    process (clk) 
    begin 
     if clk = CLK_POLARITY and clk'event then 
      data_reg <= data_in; 
     end if; 
    end process; 

Это вызывает большую проблему, как делает один IP записи, которые могут для разных конструкций нужны разная полярность синхронизации (как это сделано здесь), другую полярность сброса, а также различные стили сброса (асинхронный сброс против синхронного сброса). Я думаю, нам нужен пакет процедур, который реализует триггеры. В дополнение к специально построенным DFF с асинхронным перезагрузкой, я думаю, мы могли бы также иметь такие вещи, как DFFR (DFF с сбросом), реализация которых определяется используемым корпусом пакета.

-- In package body asynchronous resets 
procedure DFFR (
    signal Clk : std_logic ; 
    signal Reset : std_logic ; 
    signal DataIn : std_logic ; 
    signal DataOut : std_logic ; 
    constant ResetValue : std_logic 
) is 
begin 
    if Reset = RESET_POLARITY then 
    DataOut <= ResetValue ; 
    elsif Clk = CLOCK_POLARITY and Clk'event then 
    DataOut <= DataIn ; 
    end if ; 
end procedure DFFR ; 

-- In package body synchronous resets 
procedure DFFR (
    signal Clk : std_logic ; 
    signal Reset : std_logic ; 
    signal DataIn : std_logic ; 
    signal DataOut : std_logic ; 
    constant ResetValue : std_logic 
) is 
begin 
    if Clk = CLOCK_POLARITY and Clk'event then 
    if Reset = RESET_POLARITY then 
     DataOut <= ResetValue ; 
    else 
     DataOut <= DataIn ; 
    end if ; 
    end if ; 
end procedure DFFR ; 

-- In package body power on reset by initialization 
procedure DFFR (
    signal Clk : std_logic ; 
    signal Reset : std_logic ; 
    signal DataIn : std_logic ; 
    signal DataOut : std_logic ; 
    constant ResetValue : std_logic 
) is 
begin 
    if Clk = CLOCK_POLARITY and Clk'event then 
    DataOut <= DataIn ; 
    end if ; 
end procedure DFFR ; 

Проекты, которые принимают различные решения для разных тактовых доменов, нуждаются в отдельной библиотеке для каждой тактовой области.

Предстоящий IEEE 1076-2018 делает пилот для открытого источника IEEE для открытия исходных пакетов VHDL. Возможно, мы можем получить это в следующей редакции, однако в настоящее время у меня больше идей, чем у меня есть время, поэтому нам нужно больше участников.

+0

Wow, с открытым исходным кодом VHDL-пакеты ?! Надеюсь, мы не получим распространение, как это произошло с ядром Linux. Нужен какой-то надлежащий механизм обзора. Поставщики инструментов Else VHDL будут поддерживать новый стандарт исключительно выборочно (даже хуже, чем они поддерживают VHDL-2008) – JHBonarius

+0

Кстати, возможно, что касается второго кода, вам не нужны два пакета. Просто добавьте «SYNCHR_RESET» boolean generic и используйте 'if not SYNCHR_RESET и reset = RESET_POLARITY, затем [...] elsif clk = CLOCK_POLARITY и clk'event, затем, если SYNCHR_RESET и reset = RESET_POLARITY, тогда [... и т. Д.]'. Я думаю, что инструменты синтеза примут это. – JHBonarius

+0

@JHBonarius Важность открытого источника - это распространение и, в частности, распространение с помощью инструментов с открытым исходным кодом, таких как GHDL. Идя дальше, производители WRT, я только ожидаю, что они обратят внимание на версию, выпущенную из IEEE Open Source Group. Процессы все еще TBD, но я надеюсь, что это смешает некоторые из преимуществ как IEEE, так и подходов с открытым исходным кодом. –

Смежные вопросы