在VHDL中同步计算去抖按钮

时间:2015-10-31 05:38:39

标签: vhdl counter state-machine xilinx-ise spartan

以下代码是Xilinx ISE 14.7中的VDHL模块,用于计算去抖按钮(iXXX),测试它们是否达到最大值,并输出"值"对于将在7段LED上显示的std_logic_vector(oXXX)的每个累计输入(显示多路复用器和逻辑未显示)。复位(clrXX)是电路板上的开关(Digilent Spartan 3)。

在XILINX ISE中尝试合成或检查语法时,出现以下错误:

Xst:528 - Multi-source in Unit <BSO_cnt> on signal <Mcount_oOUT_s_cy<0>>; 
this signal is connected to multiple drivers.
Xst:528 - Multi-source in Unit <BSO_cnt> on signal <Mcount_oOUT_s_lut<1>>; 
this signal is connected to multiple drivers.
Xst:528 - Multi-source in Unit <BSO_cnt> on signal <Mcount_oBALL_s_cy<0>>; 
this signal is connected to multiple drivers.
Xst:528 - Multi-source in Unit <BSO_cnt> on signal <Mcount_oBALL_s_lut<1>>; 
this signal is connected to multiple drivers.
Xst:528 - Multi-source in Unit <BSO_cnt> on signal <Mcount_oBALL_s_lut<2>>; 
this signal is connected to multiple drivers.
Xst:528 - Multi-source in Unit <BSO_cnt> on signal <Mcount_oSTRIKE_s_cy<0>>; 
this signal is connected to multiple drivers.
Xst:528 - Multi-source in Unit <BSO_cnt> on signal 
    <Mcount_oSTRIKE_s_lut<1>>; this signal is connected to multiple drivers.

我该如何解决这个问题?我对VHDL很新,不知道从哪里开始。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;


entity BSO_cnt is
Port ( iBALL        : in    STD_LOGIC;
       iSTRIKE      : in    STD_LOGIC;
       iOUT         : in    STD_LOGIC;
       clrBS        : in    STD_LOGIC;
       clrOUT       : in    STD_LOGIC;
       CLK          : in    STD_LOGIC;
       oBALL        : out   STD_LOGIC_VECTOR (2 downto 0);
       oSTRIKE      : out   STD_LOGIC_VECTOR (1 downto 0);
       oOUT         : out   STD_LOGIC_VECTOR (1 downto 0));
end BSO_cnt;

architecture Behavioral of BSO_cnt is

SIGNAL iBALL_s      :   STD_LOGIC;
SIGNAL iSTRIKE_s    :   STD_LOGIC;
SIGNAL iOUT_s       :   STD_LOGIC;

SIGNAL oBALL_s      :   STD_LOGIC_VECTOR(2 DOWNTO 0);
SIGNAL oSTRIKE_s    :   STD_LOGIC_VECTOR(1 DOWNTO 0);
SIGNAL oOUT_s       :   STD_LOGIC_VECTOR(1 DOWNTO 0);

Begin

oBALL       <= oBALL_s;
oSTRIKE     <= oSTRIKE_s;
oOUT        <= oOUT_s;

BALL_PROCESS: PROCESS(CLK)
BEGIN
    IF rising_edge(CLK) THEN
        IF (clrBS = '1') THEN
            oBALL_s <= (OTHERS => '0');
        ELSIF (iBALL_s /= iBALL) THEN
            IF (iBALL = '1') THEN
                iBALL_s <= iBALL;
                oBALL_s <= STD_LOGIC_VECTOR(UNSIGNED(oBALL_s) + 1);
                IF (oBALL_s = "100") THEN
                    oBALL_s     <= (OTHERS => '0');
                    oSTRIKE_s   <= (OTHERS => '0');
                END IF; 
            END IF;
        ELSE
            iBALL_s <= iBALL;
        END IF;
    END IF;
END PROCESS;

STRIKE_PROCESS: PROCESS(CLK)
BEGIN
    IF rising_edge(CLK) THEN
        IF (clrBS = '1') THEN
            oSTRIKE_s <= (OTHERS => '0');
        ELSIF (iSTRIKE_s /= iSTRIKE) THEN
            IF (iSTRIKE = '1') THEN
                iSTRIKE_s <= iSTRIKE;
                oSTRIKE_s <= STD_LOGIC_VECTOR(UNSIGNED(oSTRIKE_s) + 1);
                IF (oSTRIKE_s = "11") THEN
                    oSTRIKE_S   <= (OTHERS => '0');
                    oBALL_s     <= (OTHERS => '0');
                    oOUT_s      <= (OTHERS => '0');
                END IF;
            END IF;
        ELSE
            iSTRIKE_s <= iSTRIKE;
        END IF;
    END IF;
END PROCESS;

OUT_PROCESS: PROCESS(CLK)
BEGIN
    IF rising_edge(CLK) THEN
        IF (clrOUT = '1') THEN
            oOUT_s <= (OTHERS => '0');
        ELSIF (iOUT_s /= iOUT) THEN
            IF (iOUT = '1') THEN
                iOUT_s <= iOUT;
                oOUT_s <= STD_LOGIC_VECTOR(UNSIGNED(oOUT_s) + 1);
                IF (oOUT_s = "11") THEN
                    oOUT_s      <= (OTHERS => '0');
                    oBALL_s     <= (OTHERS => '0');
                    oSTRIKE_s   <= (OTHERS => '0');
                END IF;
            END IF;
        ELSE
            iOUT_s <= iOUT;
        END IF;
    END IF;
END PROCESS;

end Behavioral;

2 个答案:

答案 0 :(得分:0)

您的问题可能与您从多个进程中驱动信号(oSTRIKE_soBALL_soOUT_s)这一事实有关。把它想象成短路(当不同的过程不同意价值时,你期望什么价值?)。

为什么它不会在编译和/或模拟时产生错误?

由于大多数人不了解多驱动器问题,解析功能和已解析的VHDL类型(即许多VHDL程序员甚至教师),您总是使用STD_LOGIC类型具有内置分辨率功能,可计算多个驱动过程的结果值。它的工作原理(通常会提供很多X值)...仅用于模拟。如果您使用了未解析的类型(STD_ULOGIC),那么在编译或模拟时会出现错误,因为这些类型不支持多种驱动情况。

为什么它在综合中不起作用?

您的合成器会尝试在您的目标(Spartan FPGA)的可用硬件资源上映射您的设计。 偶然你的目标没有配备可用于实现虚假设计的三态缓冲区。所以合成器会引发错误。我写的是偶然因为,如果它是另一个能够实现这个目标的目标,你可以对它进行编程并...融合它,这要归功于你的短路。有些东西可能会在你迟到之前阻止你,但你永远不会知道......毕竟你很幸运。

该怎么做?

  1. 如果您没有设计合理使用多个驱动器的东西,请不要使用STD_LOGICSTD_LOGIC_VECTOR。也就是说,设计中任何时候所有进程都以'Z'(高阻抗)驱动信号,除了最多一个驱动强值('0''1')的信号。在大多数情况下,您不希望这样做,您必须使用STD_ULOGICSTD_ULOGIC_VECTOR。如果您的老师坚持要求您使用STD_LOGICSTD_LOGIC_VECTOR,请将其发送给我。
  2. 从处理所有情况的一个过程中驱动任何信号(重置,状态......)。

答案 1 :(得分:0)

终于搞定了!问题是多个进程将值分配给同一信号。这就是我纠正错误的方法:

注意标志信号{Bmax_s,Smax_s和Omax_s}。它们由一个进程使用,以向其他进程指示它已达到其最大计数。然后,每个时钟周期,每个进程使用一个或多个标志来决定是否清除,或者在OUT_PROCESS增量的情况下,输出信号和/或更新其自己的标志。

现在每个信号只由一个进程分配!

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;


entity BSO_cnt is
    Port ( inBALL       : in  STD_LOGIC;
           inSTRIKE     : in  STD_LOGIC;
           inOUTS       : in  STD_LOGIC;
           inclrBS      : in  STD_LOGIC;
           inclrOUT     : in  STD_LOGIC;
           CLK          : in  STD_LOGIC;
           outBALL      : out  STD_LOGIC_VECTOR (1 downto 0);
           outSTRIKE    : out  STD_LOGIC_VECTOR (1 downto 0);
           outOUTS      : out  STD_LOGIC_VECTOR (1 downto 0));
end BSO_cnt;

architecture Behavioral of BSO_cnt is
    --inputs
    SIGNAL inBALL_s     :   STD_LOGIC;
    SIGNAL inSTRIKE_s   :   STD_LOGIC;
    SIGNAL inOUTS_s     :   STD_LOGIC;
    --outputs
    SIGNAL outBALL_s    :   STD_LOGIC_VECTOR(1 DOWNTO 0);
    SIGNAL outSTRIKE_s  :   STD_LOGIC_VECTOR(1 DOWNTO 0);
    SIGNAL outOUTS_s    :   STD_LOGIC_VECTOR(1 DOWNTO 0);
    --max count flags
    SIGNAL maxBALL      :   STD_LOGIC;
    SIGNAL maxSTRIKE    :   STD_LOGIC;
    SIGNAL maxOUTS      :   STD_LOGIC;

begin

    --assign signals to module outputs
    outBALL     <=  outBALL_s;
    outSTRIKE   <=  outSTRIKE_s;
    outOUTS     <=  outOUTS_s;

    --count ball pushes & update ball counter
    BALL_PROCESS: PROCESS(CLK)
    BEGIN   
        --wait for postive edge of clock
        IF rising_edge(CLK) THEN
            --check for clear ball/strike switch 
            IF (inclrBS = '1') THEN
                outBALL_s   <=  (OTHERS =>  '0');
            --check for any max count flags 
            ELSIF (maxSTRIKE = '1') OR (maxBALL = '1') OR (maxOUTS = '1') THEN
                --clear ball count
                outBALL_s   <=  (OTHERS =>  '0');
                --clear ball max count flag
                maxBALL     <=  '0';
            --check for change of ball button state
            ELSIF (inBALL_s /= inBALL) THEN
                --if pressed 
                IF inBALL = '1' THEN
                    inBALL_s        <=  inBALL;
                    -- check for walk
                    IF (outBALL_s = "11") THEN
                        --set flag
                        maxBALL <=  '1';
                    ELSE
                        --increment ball counter
                        outBALL_s   <=  STD_LOGIC_VECTOR(UNSIGNED(outBALL_s) + 1);
                    END IF;
                --if released   
                ELSE
                    inBALL_s    <=  inBALL;
                END IF;             
            END IF;         
        END IF;     
    END PROCESS;

    --Count strike pushes, and update strike counter
    STRIKE_PROCESS: PROCESS(CLK)
    BEGIN   
        --wait for positive edge of clock
        IF rising_edge(CLK) THEN
            --check for clr ball/strike switch
            IF inclrBS = '1' THEN
                outSTRIKE_s <=  (OTHERS =>  '0');
            --check for any max counts reached & update strike count
            ELSIF (maxSTRIKE = '1') OR (maxBALL = '1') OR (maxOUTS = '1') THEN
                outSTRIKE_s <=  (OTHERS =>  '0');
                --reset flag
                maxSTRIKE   <=  '0';
            --check for strike button state change
            ELSIF (inSTRIKE_s /= inSTRIKE) THEN
                --if pressed increment strike count
                IF inSTRIKE = '1' THEN
                    inSTRIKE_s      <=  inSTRIKE;
                    --check for strikeout 
                    IF (outSTRIKE_s = "10") THEN
                        --set flag
                        maxSTRIKE   <=  '1';
                    ELSE
                        --increment strike count
                        outSTRIKE_s     <=  STD_LOGIC_VECTOR(UNSIGNED(outSTRIKE_s) + 1);
                    END IF;
                --if released   
                ELSE
                    inSTRIKE_s  <=  inSTRIKE;
                END IF;             
            END IF;
        END IF; 
    END PROCESS;

    --Count out pushes, and update out counter
    OUT_PROCESS: PROCESS(CLK)
    BEGIN
        --wait for positive clock edge
        IF rising_edge(CLK) THEN
            --check for clear out switch
            IF inclrOUT = '1' THEN
                outOUTS_s   <=  (OTHERS =>  '0');
            --check for max out count
            ELSIF maxOUTS = '1' THEN
                outOUTS_s   <=  (OTHERS =>  '0');
                --clear flag
                maxOUTS     <=  '0';
            --check for strikeout
            ELSIF maxSTRIKE = '1' THEN
                --check for max outs
                IF (outOUTS_s = "10") THEN
                    --set max outs flag
                    maxOUTS <=  '1';
                ELSE
                    --increment outs
                    outOUTS_s   <=  STD_LOGIC_VECTOR(UNSIGNED(outOUTS_s) + 1);
                END IF;
            --check if button has changed states
            ELSIF (inOUTS_s /= inOUTS) THEN
                --if pressed
                IF inOUTS = '1' THEN
                    inOUTS_s    <=  inOUTS;
                    --check for change of inning
                    IF (outOUTS_s = "10") THEN
                        maxOUTS <=  '1';
                    ELSE
                        --increment outs
                        outOUTS_s   <=  STD_LOGIC_VECTOR(UNSIGNED(outOUTS_s) + 1);
                    END IF;
                --if released
                ELSE
                    inOUTS_s    <=  inOUTS;
                END IF;
            END IF;
        END IF;
    END PROCESS;

end Behavioral;

以下是来自测试台的模拟输出的图像,该测试台重置并增加球和球。罢工直到3次罢工......

ISim TestBench

对我的第一个VHDL项目来说不错:D