#state #signals #vhdl
#состояние #сигналы #vhdl
Вопрос:
У меня есть следующий код, который является частью моих цифровых часов:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
-- Seconds counter
entity SecCounter is
port(
s_enable: in std_logic;
s_load: in std_logic; -- When high, sets this counter to the value in the data inputs
s_clk: in std_logic; -- Clock
s_input: in std_logic_vector(5 downto 0); -- Data inputs
s_output: out std_logic_vector(5 downto 0); --Outputs
s_wrap: out std_logic
);
end SecCounter;
architecture imp of SecCounter is
-- Intermediate signal to mainpulate the seconds as integer
signal sec: integer range 0 to 60 := 22;
begin
s_output <= std_logic_vector(to_unsigned(sec,6)); -- Assign the input to the binary value of sec
process(s_clk, s_load, s_enable) -- If clk, enable, or load is changed
begin
s_wrap <= '0'; -- Clear the wrap
if (s_enable = '0' and s_load = '1') then -- Set the clock
sec <= to_integer(unsigned(s_input));
elsif (s_enable = '1' and rising_edge(s_clk)) then -- Increment the counter
sec <= sec 1;
end if;
if sec = 60 then -- Restart counter and toggle the next counter
sec <= 0;
s_wrap <= '1';
end if;
end process;
end imp;
s_wrap действует как разрешение для следующего счетчика. Что я пытаюсь сделать, так это то, что если этот счетчик равен 60, я хочу включить следующий счетчик для одного фронта синхронизации. Я пытаюсь сделать это, установив для s_wrap значение true, а затем значение false на следующем фронте синхронизации; однако это не меняется. Есть ли способ сделать is_wrap без состояния? ЕСЛИ нет, то как я могу решить эту проблему?
Комментарии:
1. Вы используете
ieee.std_logic_unsigned.all
, который имеет несколько проблем. Более того, он конфликтует сnumeric_std
, который вы также используете. Просто удалитеstd_logic_unsigned
предложение use.
Ответ №1:
Вы присваиваете значения sec вне предложения rising_edge (clk). И вы ничего не присваиваете sec, если s_enable = 0 и s_load = 0. Любой из этих фактов делает sec асинхронным сигналом. Если вы исправите оба, то описанная проблема должна исчезнуть.
И у Оли Чарльсворта есть хорошая мысль о проверке 59, а не 60. Тогда вам также не нужно искусственно включать несуществующие 60 в свой диапазон. И инициализация sec значением не имеет смысла. Вы должны инициализировать его в своем предложении reset.
У вас могут возникнуть другие проблемы, поскольку вы читаете s_enable, s_load и s_input асинхронно. Обычно это делается только для сигнала сброса.
Комментарии:
1. Пункт исправления: Инициализация сигналов имеет смысл при условии поддержки вашими инструментами синтеза. Я рекомендую инициализировать сигналы при объявлении и не использовать сброс, особенно если сброс иным образом не требуется. Это может привести к лучшему использованию логики во время map и P amp; R. В мире компонентов Xilinx при настройке / загрузке устройства все FFS имеют известное состояние, которое может быть настроено с помощью инициализации сигнала. Найдите «инициализация» в этой ссылке: xilinx.com/support/documentation/sw_manuals/xilinx13_1 / …
Ответ №2:
[Отказ от ответственности: Я не силен в VHDL, поэтому не могу дать совет по синтаксису.]
Я думаю, вы хотите утверждать, s_wrap
когда sec
достигнет 59, а не 60. Таким образом, на следующем фронте синхронизации счетчик минут будет отображаться s_wrap = 1
и увеличиваться, в то же время, когда этот выходной сигнал счетчика снова станет равным 0.
Я думаю, что вы хотите что-то вроде этого:
process(s_clk, s_load, s_enable) -- If clk, enable, or load is changed
begin
if (s_enable = '0' and s_load = '1') then -- Set the clock
sec <= to_integer(unsigned(s_input));
elsif (s_wrap = '1') then -- Wrap
sec <= 0;
elsif (s_enable = '1' and rising_edge(s_clk)) then -- Increment the counter
sec <= sec 1;
end if;
end process;
s_wrap <= '1' when sec = 59 else '0';
Ответ №3:
Что бы я сделал, так это объявил sec как переменную в процессе, поскольку переменные немедленно обновляются:
process(s_clk, s_load, s_enable)
variable v_sec : integer range 0 to 60;
begin
if reset = '1' then
v_sec := 0;
s_sec <= (others => '0');
s_wrap <= '0';
elsif rising_edge(s_clk) then
s_output <= std_logic_vector(to_unsigned(v_sec,6));
if s_enable = '1' then
v_sec := v_sec 1;
if v_sec = 60 then
v_sec:= 0;
s_wrap <= '1';
else
s_wrap <= '0';
end if;
else
s_wrap <= '0';
end if;
end if;
Если вы смоделируете это в modelsim, секунда будет равна 0,1,2 ….58,59,0,1,2, а s_wrap будет равен 1 каждый раз, когда секунда равна 0, за исключением первого раза, когда условие сброса устанавливает его равным 0.