Search code examples
vhdlcounterstate-machinexilinx-isespartan

Synchronously Counting Debounced Button Presses in VHDL


The following code is a VDHL module in Xilinx ISE 14.7 that counts debounced button presses (iXXX), tests to see if they have reached a max, and outputs a "value" for each accumulated input to a std_logic_vector (oXXX) that will be displayed on a 7-segment LED (display mux & logic not shown). The resets (clrXX) are switches on the board (Digilent Spartan 3).

When trying to synthesize or checking syntax in XILINX ISE, I get the following errors:

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.

How can I fix this? I am fairly new to VHDL, and not sure where to start.

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;

Solution

  • Your problem has probably something to do with the fact that you drive signals (oSTRIKE_s, oBALL_s, oOUT_s) from several processes. Think of this as short circuits (what value do you expect when the different processes do not agree on the value?).

    Why then doesn't it produce errors at compilation and / or simulation?

    As most people who do not know about the multiple drive problem, the resolution functions and the resolved types of VHDL (that is, a lot of VHDL programmers and even teachers), you always use the STD_LOGIC type that has a built-in resolution function to compute the resulting value of multiple driving processes. And it works (usually giving a lot of X values)... for simulation only. If you had used an unresolved type (STD_ULOGIC) instead you would have had an error at compilation or simulation because these types do not support multiple drive situations.

    Why does it not work in synthesis?

    Your synthesiser tries to map your design on the available hardware resources of your target (Spartan FPGA). By chance your target is not equipped with the three-state buffers that could be used to implement your bogus design. So the synthesiser raises errors. I wrote by chance because, if it had been another target capable of implementing this, you could have programmed it and... fuse it, thanks to your nice short circuits. Something would probably have prevented you before it is to late but you never know... So you are lucky, after all.

    What to do then?

    1. Never use STD_LOGIC and STD_LOGIC_VECTOR when you do not design something that reasonably makes use of multiple drive. That is, a design where at any time all processes drive the signal with 'Z' (high impedance) except, at most, one that drives a strong value ('0'or '1'). In most cases you do not want to do this and you must use STD_ULOGIC and STD_ULOGIC_VECTOR. If your teacher insists that you use STD_LOGIC and STD_LOGIC_VECTOR, send it to me.
    2. Drive any signal from one single process in which you deal with all situations (reset, states...).