#counter #vhdl #flip-flop
#счетчик #vhdl #триггер
Вопрос:
Я смоделировал 4-разрядный кольцевой счетчик с использованием D-триггера.
Общий триггер находится в отдельном файле, включенном в мою рабочую область. Триггер D работает правильно (выдает правильную форму выходного сигнала).
Это код кольцевого счетчика:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity ring4counter is
port (
clk: std_logic;
output: out std_logic_vector(3 downto 0));
end ring4counter;
architecture ring4counter_arch of ring4counter is
component dff
port (
clk: std_logic;
d: in std_logic;
q: out std_logic;
qbar: out std_logic);
end component;
signal temp:std_logic_vector(3 downto 0):=(others=>'0');
begin
r1: dff port map(clk, temp(3), temp(0));
r2: dff port map(clk, temp(0), temp(1));
r3: dff port map(clk, temp(1), temp(2));
r4: dff port map(clk, temp(2), temp(3));
output <= temp;
end ring4counter_arch;
Вот тестовый код для кольцевого счетчика:
library ieee;
use ieee.std_logic_1164.all;
entity ring4_tb is end ring4_tb ;
architecture arch of ring4_tb is
component tbc is
port (
clk: std_logic;
output: out std_logic_vector(3 downto 0));
end component ;
component dff
port (
clk: std_logic;
d: in std_logic;
q: out std_logic;
qbar: out std_logic);
end component;
constant period : time := 50 ns ;
signal clk : std_logic := '0' ;
signal done : boolean := false ;
signal output : std_logic_vector(3 downto 0) ;
shared variable cycle : natural := 0 ;
signal temp:std_logic_vector(3 downto 0):=(others=>'0');
begin
-- this is the unit under test
u1: tbc
port map(
clk => clk,
output => output) ;
clkprocess: process(done, clk)
begin
if (not done) then
if (clk = '1') then
cycle := cycle 1 ;
end if ;
clk <= not clk after period / 2 ;
end if ;
end process ;
r1: dff port map(clk, temp(3), temp(0));
r2: dff port map(clk, temp(0), temp(1));
r3: dff port map(clk, temp(1), temp(2));
r4: dff port map(clk, temp(2), temp(3));
output <= temp;
testbench: process
begin
wait until (clk = '0') ;
temp <= "1000";
wait for period*4 ;
done <= true ; -- force the clock process to shutdown
wait ; -- this waits forever
end process ;
end arch ;
Но форма сигнала для «вывода» — это «U» для всех битов.
Где я ошибаюсь?
Комментарии:
1. Я знаю, что это более старый пост, но я хотел бы сделать стилистический комментарий — если вы когда-нибудь сделаете назначение должности по позиции в реальном мире, вас выследят и побьют. Никогда не делайте этого.
r1: dff port map(clk=>clk, d=>temp(3), q=>temp(0));
допустимо использовать одну строку для простого компонента (но вас также высмеяли бы за то, что вам нужен компонент DFF).2. ха-ха, я не думаю, что меня побьют! Я знаю, что мне не нужен DFF для кольцевого счетчика. Но когда вы учитесь (я имею в виду, что я учусь), имеет смысл выбрать неочевидный маршрут.
Ответ №1:
В процессе testbench, когда вы пытаетесь инициализировать temp на «1000», триггеры по-прежнему также передают сигнал temp, так что у вас фактически продолжается борьба с шиной.
Комментарии:
1. Да, у вас не может быть нескольких вещей, управляющих шиной (в целом)
2. могу ли я как-нибудь это исправить? Я не очень хорошо знаю VHDL. Я даже опустил строку temp <= «1000», по-прежнему без изменений.
3. Вам нужно изменить способ инициализации общих триггеров. Одним из способов было бы разделить входы D и Q и явно загрузить значение инициализации при сбросе. Я не могу поместить форматированный код в комментарии, но r1: карта портов dff (clk, temp_in (3), temp (0)); temp_in <= «1000» при сбросе = ‘1’ else temp; должен направить вас в правильном направлении.
Ответ №2:
temp
Для настройки сигнала используйте инициализацию в вашем кольцевом счетчике.
Обратите внимание, что это может неправильно синтезироваться в зависимости от вашей архитектуры и инструмента синтеза.
Наиболее общий способ сделать это — добавить сигнал сброса ко всем DFF, кроме on, и наложить на него предустановленный сигнал. Затем вы утверждаете сброс в начале, который установит DFF на хорошее значение.
Вот более простая версия вашего кода, которая делает это и позволяет избежать необходимости использования явных DFF. Вы также можете изменить ширину temp
, и код сделает все остальное за вас:
process (clk)
begin
if reset = '1' then
temp <= (0=>'1', others => '0'); -- set one bit high, the others low.
elsif rising_edge(clk) then
-- take the high bit and move it to the low bit.
-- Move the other bits left 1 place
temp <= temp(temp'high-1 downto 0) amp; temp(temp'high);
end if;
end process;
(Примечание: код, только что введенный в сообщение, может содержать синтаксические опечатки!)
Кстати, shared variable
s — плохая идея, если они не имеют protected
типов. У них могут быть условия гонки.
Ответ №3:
Одна вещь, которую нужно сделать, это добавить разрешающий сигнал к D триггерам. если вы хотите сбросить схему, сделайте сигнал включения низким, а затем измените температуру на «1000».
r1: dff port map(clk, temp(3), temp(0), enable);
process(clk,reset)
begin
if(rising_edge(clk)) then
if( reset='1') then
enable='0';
temp <= "1000";
else
enable <= '1';
end if;
end if;
end process;
Комментарии:
1. Я не думаю, что это сработает — DFF все еще передают сигнал даже при сбросе.
2. @Martin : Хорошо. спасибо за примечание. Но что, если я определю триггер D таким образом, чтобы Q <=D назначался только при высоком уровне сигнала включения. В противном случае назначение не выполнено. Будет ли это работать в этом случае?
3. Это не происходит, когда происходит назначение. Тот факт, что процесс имеет назначение где-то в нем, создает «драйвер», и драйверы затем конфликтуют. В VHDL нет таких вещей, как неактивный драйвер. При
std_logic
этом у вас может быть драйвер Z, который затем разрешает так, как вы могли ожидать, но это все еще драйвер.