题目描述
编写一个十进制加法器,为上升沿触发一次加法,输出每五次翻转一次方向。
产生毛刺的程序
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY fractional_frequency IS
PORT(
CLKIN: IN BIT;
CLKOUT: OUT BIT
);
END;
ARCHITECTURE bhv OF fractional_frequency IS
SIGNAL A: INTEGER RANGE 0 to 15;
BEGIN
PROCESS(CLKIN) BEGIN
IF (CLKIN'EVENT AND CLKIN='1') THEN
IF (A < 9) THEN
A <= A + 1;
ELSE
A <= 0;
END IF;
END IF;
IF (A < 5) THEN
CLKOUT <= '1';
ELSE
CLKOUT <= '0';
END IF;
END PROCESS;
END bhv;
输出波形为
(上面为CLKIN,下面为CLKOUT)
明显可见,在CLKOUT为低电平时,出现了竞争与冒险的情况,
竞争与冒险发生的原因
-
这里为什么会出现竞争与冒险呢?:
在CLKOUT为低电平时,A的值大于等于5,假如在第六个上升沿触发时,A做加法运算,A的值由0101,变成了0110,在变化过程中,0101的低2位由01变成了10,从而使得A的值由5变成了6,但是0101的低2位不会同时翻转(由于电流通过不同的电路的时间可能不同),有可能是第0位的1先变成0,也有可能是第1位的0现变成1,如果是第0位的1先变成0,则A的值先变成了0100,由于A小于5,CLKOUT为高电平,但是A的第1位很快就由0变成1,A的值又变成了0110,A大于5,又变成了低电平,由于第0位和第1位变化的时间间隔很短,所以高电平的时间很短,只是在一瞬间发生了翻转,所以出现如图箭头所示的毛刺,其他毛刺原理相同。
那么我们如何在这一题上解决竞争与冒险呢?
修改程序,消除毛刺。
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY fractional_frequency IS
PORT(
CLKIN: IN BIT;
CLKOUT: OUT BIT
);
END;
ARCHITECTURE bhv OF fractional_frequency IS
SIGNAL A: INTEGER RANGE 0 to 15;
BEGIN
PROCESS(CLKIN) BEGIN
IF (CLKIN'EVENT AND CLKIN='1') THEN
IF (A < 9) THEN
A <= A + 1;
ELSE
A <= 0;
END IF;
END IF;
END PROCESS;
PROCESS BEGIN
wait until CLKIN='1'; -- VHDL要求当进程语句中使用wait语句后,就不必列出敏感信号
IF (A < 5) THEN -- 含义是:如果CLKIN还不是1,CLKOUT就保持原值不变,直到CLKIN等于1时才对CLKOUT赋值更新
CLKOUT <= '1';
ELSE
CLKOUT <= '0';
END IF;
END PROCESS;
END bhv;
上图可见毛刺消失。
方法2
使组合逻辑电路变成时序逻辑电路
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity half is
port (clkin: in std_logic;
clkout: out std_logic );
end;
architecture bhv of half is
signal A: integer range 0 to 15;
begin
process(clkin) begin
if clkin'event and clkin='1' then
if A<9 then
A <= A + 1;
else
A <= 0;
end if;
if A<5 then
clkout <= '1';
else
clkout <= '0';
end if;
end if;
end process;
end bhv;