«Незакрытая» выборка и защелки в VHDL

#vhdl

#vhdl

Вопрос:

Я почти всегда сталкиваюсь с этой проблемой в VHDL, и это, вероятно, связано с моим образом мышления; поэтому я надеюсь, что кто-нибудь может указать правильный способ думать об этом.

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

Итак, моя первая попытка обычно самая простая из возможных — поместить что-то подобное в мой файл VHDL:

 wdata_reg <= wdata_in when (en_n = '0');  
 

… что подразумевает незакрытую / асинхронную схему — и хотя я получаю в результатах моделирования то, что ожидаю, xst например, synthnesizer ISE WebPack выдает:

WARNING:Xst:737 - Found 8-bit latch for signal <wdata_reg>. Latches may be generated from incomplete case or if statements. We do not recommend the use of latches in FPGA/CPLD designs, as they may lead to timing problems.

Опять же, я предполагаю, что я только что описал (незамкнутый / асинхронный регистр «выборки») — это, по определению, защелка? Итак, я никогда не уверен, хочу ли я этого там или нет.

С другой стороны (если я правильно помню) Я когда-то также пытался написать подобный код в конечном автомате (так, с тактовой частотой):

 ...
IF en_n = '0' THEN
  wdata_reg <= wdata_in;
END IF;
...
 

… и, я полагаю, компилятор не жаловался на это (и он работал, как ожидалось).

Итак, я думаю, мой вопрос можно сформулировать так: всякий раз, когда мне нужно «выполнить выборку» в регистр, должен ли я всегда делать это из конечного автомата (или тактовой схемы) — или есть альтернатива? Например, я могу попытаться обмануть «неполный… если операторы » как это:

 wd_read_o <= d_io when (wrd_n = '0') else wd_read_o;
 

… (другими словами: … иначе назначьте себя самому себе) — но компилятор видит мои noobery и в любом случае выдает ole WARNING:Xst:737 🙂

Я был бы признателен за некоторые рекомендации о том, как думать об этом, чтобы я не сталкивался с этой дилеммой каждый раз, когда мне нужен регистр 🙂 Приветствия!

Ответ №1:

Итак, моя первая попытка обычно самая простая из возможных — поместить что-то подобное в мой файл VHDL:

   wdata_reg <= wdata_in when (en_n = '0');  
 

Да, это классическая защелка. Это провод, когда en_n равно нулю, и когда он равен единице, wdata_reg сохранит его значение, поскольку ничто не управляет им.

Опять же, я предполагаю, что я только что описал (незамкнутый / асинхронный регистр «выборки») — это, по определению, защелка? Итак, я никогда не уверен, хочу ли я этого там или нет.

Защелки действительно полезны только при пересечении тактовых доменов, чтобы избежать сбоев. В общем, они вам не нужны.

Версия внутри синхронизированного процесса сгенерирует регистр, потому что он синхронизирован (сюрприз!).). Теперь у вас есть два задействованных сигнала: синхронизация и включение. Разница в том, что касается VHDL, заключается в том, что одно назначение происходит непрерывно (защелка), а одно происходит только на фронте синхронизации (регистр)

Итак, я думаю, мой вопрос можно сформулировать так: всякий раз, когда мне нужно «выполнить выборку» в регистр, должен ли я всегда делать это из конечного автомата (или тактовой схемы) — или есть альтернатива?

Это должен быть синхронизированный процесс. Регистру нужны часы.

Например, я могу попытаться обмануть «неполный… если операторы » как это:

 wd_read_o <= d_io when (wrd_n = '0') else wd_read_o;
 

Это точно такой же оператор, как и раньше. Предложение else выведено из предыдущей версии. Важным моментом является то, что когда wrd_n равен нулю, любые переходы в d_io будут происходить в wd_read_o, это не поведение регистра. Это защелка.

Я был бы признателен за некоторые рекомендации о том, как думать об этом, чтобы я не сталкивался с этой дилеммой каждый раз, когда мне нужен регистр 🙂 Приветствия!

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


Другой распространенный способ вывода защелок без смысла — это если у вас есть асинхронный процесс, который имеет путь через is, который не обновляет сигнал.

 p_async : process (wibble, wobble)
begin
  if (wibble = '1' and wobble = '0') then
      next_reg_b <= data_in;
  end if;
end process;
 

Если if оператор неверен, next_reg_b он не будет обновляться и должен будет сохранить его значение. Это создает защелку, поскольку ей необходимо сохранить значение, но не нужна защелка (или даже регистр), просто немного логики. Решение состоит в том, чтобы добавить назначение по умолчанию.

 p_async : process (wibble, wobble, reg_b)
begin
  next_reg_b <= reg_b;
  if (wibble = '1' and wobble = '0') then
      next_reg_b <= data_in;
  end if;
end process;
 

Now next_reg_b всегда присваивается, независимо от состояния wibble и wobble . Нет защелки.

Комментарии:

1. Потрясающе — большое спасибо за это, @Paul S — именно такая критика мне была нужна 🙂 Приветствия!

Ответ №2:

Во-первых, я бы начал с ознакомления с обзором защелок: почему я должен заботиться о защелках?

Вы можете построить схему, которую вы описываете, с триггером, запускаемым по краю, следующим образом. Это будет передаваться input , когда enable активен или последнее значение input , когда enable неактивно.

 last_input_set <= input WHEN enable='1' ELSE
                  last_input_reg;
output <= last_input_set;

if rising_edge(clk) then
    last_input_reg <= last_input_set;
end if;
 

Комментарии:

1. Приветствия @crewbum — очень хорошая ссылка; и еще более приятный фрагмент кода: наличие обоих last_input_reg и last_input_set помогает мне лучше взглянуть на вещи 🙂 Большое, большое спасибо!

Ответ №3:

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

Это может быть традиционным

 process(clk)
begin
  if rising_edge(clk) then
    if en = '1' then
      latched <= raw;
     end if;
  end if;
end process;
 

Или аккуратнее (если это все, что вы делаете):

 latched <= raw when rising_edge(clk) and en = '1';
 

Комментарии:

1. Большое спасибо за это @Martin Thompson — здорово иметь эти фрагменты для справки… Приветствия!