我在某些同步计数器的VHDL代码中存在时序问题。我无法弄清楚为什么计数器以1个时钟脉冲前进两次。我已经尝试了一切,包括在D-flip上添加不必要的代码,试图让它正常工作。这是一个类,我们必须使用我们自己的模型而不是库块。我是一名软件程序员,参加这门课程并且有时会使用“即时”作业而不是程序中的“连续”作业。
如果有人能指出我正确的方向,我会很感激。谢谢
--D-FlipFlop
ENTITY D_flipflop IS
PORT ( D, Clock, Reset : IN STD_LOGIC ;
Q : OUT STD_LOGIC) ;
END D_flipflop ;
ARCHITECTURE Behavior OF D_flipflop IS
Signal Q_buff : STD_LOGIC := '0';
BEGIN
Q <= Q_buff;
PROCESS ( Clock, Reset )
BEGIN
IF (Reset = '0') THEN
Q_buff <= '0';
ElSE
IF RISING_EDGE(Clock) THEN
IF (D = '1') THEN -- Was D <=Q changed as a trial fix
Q_buff <= '1';
ELSE
Q_buff <= '0';
END IF;
END IF;
END IF ;
END PROCESS ;
END Behavior ;
--4 bit Synchronous counter with load
entity SyncCounter is
Port ( CLOCK : in STD_LOGIC;
D : in STD_LOGIC_VECTOR (3 downto 0);
Q : inout STD_LOGIC_VECTOR (3 downto 0);
CE : in STD_LOGIC;
Load : in STD_LOGIC;
CEO : out STD_LOGIC;
Reset : in STD_LOGIC);
end SyncCounter;
architecture Behavioral of SyncCounter is
SIGNAL ND0, ND1, ND2, ND3, CE_CLOCK : STD_LOGIC := '0';
component D_flipflop IS
PORT ( D, CLOCK, RESET : IN STD_LOGIC ;
Q : OUT STD_LOGIC) ;
END component ;
begin
CE_CLOCK <= (CLOCK and (CE or Load));
ND0 <= (NOT Q(0) and NOT Load)
or (D(0) and Load);
SC_D0: D_flipflop PORT MAP ( ND0, CE_CLOCK, Reset, Q(0));
ND1 <= (((NOT Q(0) AND Q(1)) OR (Q(0) AND NOT Q(1))) and NOT LOAD) -- (Q(0) XOR Q(1))
or (D(1) and Load);
SC_D1: D_flipflop PORT MAP ( ND1, CE_CLOCK, Reset, Q(1));
ND2 <= (((Q(0) and Q(1) and NOT Q(2)) or (Q(2) and (NOT Q(0) or NOT Q(1)))) AND NOT Load)
or (D(2) and Load);
SC_D2: D_flipflop PORT MAP ( ND2, CE_CLOCK, Reset, Q(2));
ND3 <= ((((NOT Q(0) or NOT Q(1) or NOT Q(2)) AND Q(3)) OR (Q(0) and Q(1) and Q(2) and NOT Q(3))) AND NOT Load)
or (D(3) and Load);
SC_D3: D_flipflop PORT MAP ( ND3, CE_CLOCK, Reset, Q(3));
CEO <= Q(0) AND Q(1) AND Q(2) AND Q(3) AND CE; --- CEO output
end Behavioral;
图如下所示。
答案 0 :(得分:1)
问题可能是CE_CLOCK <= (CLOCK and (CE or Load));
时钟逻辑的结果,因为这可能会为多个增量时间步骤创建多个时钟转换,但是在相同的仿真时间。
如果触发器更新必须是有条件的,那么在翻转流程上启用时钟,使用以下代码:
process (clk, rst) is
begin
if rising_edge(clk) then
if cen = '1' then -- Clock Enable (cen)
q <= d;
end if;
end if;
if rst = '1' then
q <= '0';
end if;
end process;
答案 1 :(得分:1)
莫滕的回答并不是整个故事
为了与Morten的答案保持一致 - 使用启用,将计数器中的D FF视为具有HOLD(Q),TOGGLE(非Q)和LOAD(D)项的输入多路复用器。
在此示例中,等效多路复用器显示为cntdin:
library ieee;
use ieee.std_logic_1164.all;
entity cntr4 is
port (
d: in std_logic_vector (3 downto 0);
load: in std_logic;
reset: in std_logic;
enable: in std_logic;
clk: in std_logic;
q: out std_logic_vector (3 downto 0);
enab_out: out std_logic
);
end ;
library ieee;
use ieee.std_logic_1164.all;
entity dff is
port (
d: in std_logic;
clk: in std_logic;
q: out std_logic
);
end entity;
architecture behave of dff is
begin
process(clk)
begin
if rising_edge(clk) then
q <= d;
end if;
end process;
end architecture;
architecture struct of cntr4 is
component dff is
port (
d: in std_logic;
clk: in std_logic;
q: out std_logic
);
end component;
signal cntincr,cntd,cntq: std_logic_vector (q'range);
begin
cnt_incr: -- incrementer
process(cntq)
begin
cntincr(0) <= not cntq(0);
cntincr(1) <= cntq(1) xor cntq(0);
cntincr(2) <= cntq(2) xor (cntq(0) and cntq(1));
cntincr(3) <= cntq(3) xor (cntq(0) and cntq(1) and cntq(2));
end process;
cntdin:
for i in cntd'range generate
cntd(i) <= (cntq(i) and not reset and not enable) or
(d(i) and not reset and enable and load) or
(cntincr(i) and not reset and enable and not load);
end generate;
cntreg:
for i in cntq'range generate
D_FF: dff
port map (
d => cntd(i),
clk => clk,
q => cntq(i)
);
end generate;
cntptr:
q <= cntq;
en_out:
enab_out <= enable and cntq(0) and cntq(1) and cntq(2) and cntq(3);
end architecture;
在此示例中,您几乎可以免费获得同步复位(AND / OR中每个AND的一个输入)。它使用触发器而无需异步复位或启用。
借用cntr4的测试平台并添加not_reset以反转重置以匹配SyncCounter:
library ieee;
use ieee.std_logic_1164.all;
entity cntr4_tb is
end entity;
architecture foo of cntr4_tb is
signal d: std_logic_vector (3 downto 0);
signal load: std_logic;
signal reset: std_logic;
signal enable: std_logic;
signal clk: std_logic := '1';
signal q: std_logic_vector (3 downto 0);
signal enab_out: std_logic;
signal reset_not: std_logic;
begin
reset_not <= not reset;
DUT:
entity
work.SyncCounter
port map (
CLOCK => clk,
D => d,
Q => q,
CE => enable,
Load => load,
Reset => reset_not,
CEO => enab_out
);
CLOCK:
process
begin
wait for 10 ns;
clk <= not clk;
if Now > 720 ns then
wait;
end if;
end process;
STIMULUS:
process
begin
wait for 10 ns;
reset <= '1';
load <= '0';
d <= X"5";
enable <= '0';
wait for 30 ns;
reset <= '0';
wait for 30 ns;
load <= '1';
enable <= '1';
wait for 20 ns;
load <= '0';
enable <= '0';
wait for 20 ns;
enable <= '1';
wait for 80 ns;
enable <= '0';
wait for 20 ns;
enable <= '1';
wait;
end process;
end architecture;
我们发现你的SyncCounter显然有效:
那为什么会有效?
如果您注意到所有输入激励有效地匹配时钟边沿,并且具有0 delta延迟差异,并且恰好在另一个时钟边沿上运行。
如果没有CE和负载上的增量周期相干转换,您可以获得由增量周期偏移引起的额外正时钟边沿。这里有几条消息。
门控时钟应该与恐惧一起使用。
时钟门的输出通常应为高电平,通常不像CE_CLOCK那样低。您将使用CLOCK的低波特率在CE_CLOCK上生成正转换,而不是使用CLOCK的Load或CE AND&d的正事务。
测试平台导致CE_CLOCK在安全时间内被门控,因此SyncCounter可以工作。
您可以使用带有启用功能的触发器,包含启用的输入多路复用器或尝试切换CE_CLOCK空闲状态的意义。
它没有意外复位,启用和加载启用通常是否定的。当门控时钟时,可以使用NOT AND NOT门(OR门De Morgan等效门)完成,从而节省门延迟。门控时钟的时钟偏差可以减少到一个门延迟。
门控时钟的吸引力来自节电。
如果你想合成计数器,你可能会发现使用门控时钟有点强烈不鼓励。
显示时钟故障
因为我们可能没有将delta delta循环粒度事件发布到波形转储的模拟器,所以两者 CE和早期加载1 nsec:
在此波形捕获中,您可以清楚地看到故障以及计数器的位置是双倍的&#39;递增。
您还可以注意到时钟上升沿由时钟边沿前1 ns的CE和Load,Q(3 downto 0)驱动。
将CE_CLOCK更改为常高:
-- CE_CLOCK <= (CLOCK and (CE or Load));
CE_CLOCK <= CLOCK or not (CE or Load);
失去毛刺,并在时钟边缘排列Q(3 downto 0)过渡: