#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 — здорово иметь эти фрагменты для справки… Приветствия!