Как сделать выходной сигнал VHDL без состояния

#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.