(VHDL) Issue with outputs in vhdl entity

2.6k views Asked by At

I have problems with the output of the vhdl entity that always sends out U. I looked at various forums but I could not find a solution.

The project is a 5-story lift that has to wait 5 seconds to close the door and 10 seconds to get to the next plane up to the target. Use Logisim (v 2.13.22) and ghdl (v 0.29.1).

Does anyone have any idea what the problem might be? Thanks in advance

Main circuit of the project

vhdl simulator log

Here the vhdl code i made.

    library ieee;
       use ieee.std_logic_1164.all;
       use ieee.numeric_std.all;



    entity Elevator is
        Port (
            clk : in std_logic;

            rst : in std_logic;
            rstPorta : in std_logic;
            rstMotore : in std_logic;

            zero : in std_logic;
            one : in std_logic;
            two : in std_logic;
            three : in std_logic;
            four : in std_logic;

            upEngine : out std_logic;
            downEngine : out std_logic;

            ledReady: out std_logic;
            ledUp: out std_logic;
            ledDown: out std_logic;
            ledDoorOpen: out std_logic;
            ledDoorClosed: out std_logic;

            ledBusy: out std_logic;
            ledUsable: out std_logic;

            doorOpenEngine : out std_logic;
            doorCloseEngine : out std_logic;

            cntPiano : out std_logic_vector(4 downto 0)
        );
    end Elevator;

    architecture Ascensore of Elevator is
        type state_type is (s0,s1,s2,s3,s4);
        signal current_s,next_s: state_type;
        signal cf, df: std_logic_vector(3 downto 0);    -- vettore a 4 bit
        signal countPorta: std_logic_vector(2 downto 0);    -- vettore a 3 bit
        signal countMotore: std_logic_vector(3 downto 0);   -- vettore a 4 bit

        begin

        -- Questo processo modifica il segnale countPorta in modo tale da segnalare il tempo rimanente prima della chiusura della porta
        process (clk,rstPorta)
            begin
            if (rstPorta='1') then countPorta <= "000"; -- Condizione di bypass della porta, apre la porta senza tempi d'attesa, per casi di emergenza
                elsif (clk'event and clk='1') then
                    if (countPorta = "100") then countPorta <= "011";
                        elsif (countPorta = "011") then countPorta <= "010";
                        elsif (countPorta = "010") then countPorta <= "001";
                        else countPorta <= "000";
                    end if;
            end if;
        end process;

        -- Questo processo modifica il segnale countMotore in modo tale da segnalare il tempo necessario all'arrivo al piano successivo
        process (clk,rstMotore)
            begin
            if (rstMotore='1') then countMotore <= "0000";  -- Condizione di bypass del motore, ferma lo spostamento in casi di emergenza
                elsif (clk'event and clk='1') then
                    if (countMotore = "1001") then countMotore <= "1000";
                        elsif (countMotore = "1000") then countMotore <= "0111";
                        elsif (countMotore = "0111") then countMotore <= "0110";
                        elsif (countMotore = "0110") then countMotore <= "0101";
                        elsif (countMotore = "0101") then countMotore <= "0100";
                        elsif (countMotore = "0100") then countMotore <= "0011";
                        elsif (countMotore = "0011") then countMotore <= "0010";
                        elsif (countMotore = "0010") then countMotore <= "0001";
                        else countMotore <= "0000";
                    end if;
            end if;
        end process;


        -- Questo processo serve a controllare le chiamate dell ascensore nei vari piani
        process (clk,rst)
            begin
            -- si inizializza ascensore considerando che esso parta dal piano 0 in una condizione priva di richieste esterne (stato 3)
            if (rst='1') then
                df <= "0000";
                cf <= "0000";

                upEngine <= '1';
                downEngine <= '1';

                ledReady <= '1';
                ledUp <= '1';
                ledDown <= '1';
                ledDoorOpen <= '1';
                ledDoorClosed <= '1';

                ledBusy <= '1';
                ledUsable <= '1';

                doorOpenEngine <= '1';
                doorCloseEngine <= '1';

                current_s <= s3;
            end if;

            -- verifica se vi sono state richieste nei vari piani ad ogni ciclo di clock assegnando a df (desired floor) il piano della richiesta
            if (clk'event and clk='1') then
                if (zero = '1') then df <= "0000";
                    elsif (one = '1') then df <= "0001";
                    elsif (two = '1') then df <= "0010";
                    elsif (three = '1') then df <= "0011";
                    elsif (four = '1') then df <= "0100";
                end if;

                -- lo stato corrente corrisponde allo stato successivo
                current_s <= next_s;
            end if;

        end process;



        -- Processo Ascensore
        process (current_s, cf, df, clk)
            begin
            if (clk'event and clk='1') then
                case current_s is
                    -- STATO 0: fase di salita ascensore fino a che il piano desiderato non e' uguale al piano corrente
                    when s0 =>
                        if(cf < df) then

                            upEngine <= '1';

                            -- se il motore non e' ancora arrivato al piano resta nello Stato 0
                            if((countMotore= "1001") or (countMotore= "1000") or (countMotore= "0111") or (countMotore= "0110") or (countMotore= "0101") or (countMotore= "0100") or (countMotore = "0011") or (countMotore = "0010") or (countMotore = "0001"))
                                then then next_s <= s0;
                            end if;

                            -- se sono passati 10 sec, siamo arrivati al piano. cf verra' aumentato
                            if(countMotore = "0000") then
                                if (cf = "0000") then cf <= "0001";
                                    elsif (cf = "0001") then cf <= "0010";
                                    elsif (cf = "0010") then cf <= "0011";
                                    elsif (cf = "0011") then cf <= "0100";
                                end if;
                            end if;

                            -- se il piano desiderato e' > del corrente fai un altro ciclo dello Stato 0
                            if(cf < df) then
                                next_s <= s0;
                            end if;

                            -- se il piano desiderato e' = al corrente vai nello Stato 2
                            if(cf = df) then
                                ledUp <= '0';
                                upEngine <= '0';
                                next_s <= s2;
                                countPorta <= "100";
                            end if;


                        end if;

                    -- STATO 1: fase di discesa ascensore fino a che il piano desiderato non e' uguale al piano corrente
                    when s1 =>
                        if(cf > df) then

                            downEngine <= '1';

                            -- se il motore non e' ancora arrivato al piano resta nello Stato 1
                            if((countMotore= "1001") or (countMotore= "1000") or (countMotore= "0111") or (countMotore= "0110") or (countMotore= "0101") or (countMotore= "0100") or (countMotore = "0011") or (countMotore = "0010") or (countMotore = "0001")) then
                                elsif(countMotore = "0000") then next_s <= s1;
                            end if;

                            -- se sono passati 10 sec, siamo arrivati al piano. cf verra' diminuito
                            if(countMotore = "0000") then
                                if (cf = "0100") then cf <= "0011";
                                    elsif (cf = "0011") then cf <= "0010";
                                    elsif (cf = "0010") then cf <= "0001";
                                    elsif (cf = "0001") then cf <= "0000";
                                    else cf <= cf;
                                end if;
                            end if;

                            -- se il piano desiderato e' < del corrente fai un altro ciclo dello Stato 1
                            if (cf > df) then
                                next_s <= s1;
                            end if;

                            -- se il piano desiderato e' = al corrente vai nello Stato 2
                            if(cf = df) then
                                ledDown <= '0';
                                downEngine <= '0';
                                next_s <= s2;
                                countPorta <= "100";
                            end if;
                        end if;

                    -- STATO 2: fase di apertura della porta nel piano desiderato
                    when s2 =>
                        if(countPorta = "000") then next_s <= s3;
                        else next_s <= s2;
                        end if;


                    -- STATO 3: ascensore in attesa di richieste con porta aperta
                    when s3 =>
                        doorOpenEngine <= '1';
                        doorCloseEngine <= '0';
                        ledDoorOpen <= '1';
                        ledDoorClosed <= '0';
                        ledReady <= '1';
                        ledUp <= '0';
                        ledDown <= '0';
                        ledBusy <= '0';
                        ledUsable <= '1';
                        if(cf = df) then
                            next_s <= s3;
                        end if;
                        if ((cf<df) or (cf>df)) then
                            countPorta <= "100";
                            next_s <= s4;
                        end if;

                    -- STATO 4: fase di chiusura della porta e selezione dello stato successivo per la salita (Stato 0) o discesa (Stato 1) dell'ascensore
                    when s4 =>
                        if((countPorta = "100") or (countPorta = "011") or (countPorta = "010") or (countPorta = "001")) then
                            next_s <= s4;

                            elsif((countPorta = "000") and (cf<df)) then
                                doorOpenEngine <= '0';
                                doorCloseEngine <= '1';
                                ledDoorOpen <= '0';
                                ledDoorClosed <= '1';
                                ledReady <= '0';
                                ledUp <= '1';
                                ledDown <= '0';
                                ledBusy <= '1';
                                ledUsable <= '0';
                                countMotore <= "1001";
                                next_s <= s0;
                            elsif((countPorta = "000") and (cf>df)) then
                                doorOpenEngine <= '0';
                                doorCloseEngine <= '1';
                                ledDoorOpen <= '0';
                                ledDoorClosed <= '1';
                                ledReady <= '0';
                                ledUp <= '0';
                                ledDown <= '1';
                                ledBusy <= '1';
                                ledUsable <= '0';
                                countMotore <= "1001";
                                next_s <= s1;
                        end if;
                end case;
            end if;
        end process;


    end Ascensore;
2

There are 2 answers

0
FPGA-guy On

I am not sure where you are at with this design but I am hoping you made some progress on your own since posting.

Now, to the heart of your problem. The signals upEngine, downEngine, ... , doorCloseEngine and current_s are not assigned in a single process. They are driven in both the third and fourth process statements which therefore constitutes a case of multiply driven nets.

In your simulator, look for a command that will report the drivers for any given signal. Here is what I see in Vivado for the upEngine signal (your line numbers might not match exactly -- I was tweaking the code):

 report_drivers {/Elevator/upEngine}
 Drivers for /Elevator/upEngine
   U : Net /Elevator/upEngine
     U : Driver /Elevator/line__125 at C:/temp/new1.vhd:125
     1 : Driver /Elevator/line__82 at C:/temp/new1.vhd:82

This is somewhat subtle. VHDL employs a resolution function to decide what to do when there are multiple drivers. In this case, since the signals are std_logic type, the std_logic_1164 library specifies the resolution function and it says that 'U' always wins in a contest between two values. So, no matter what is driven in the third process, the uninitialized signals in the 4th process will contribute 'U' and determine the signal state. (At least until the state machine gets to a state that actually drives a known value onto upEngine).

You might have noticed in your simulation that signals ledUp and ledDown were 'X' after the first rising clock edge. That is because they are both multiply driven as well -- however one driver contributes '1' and the other '0'. The resolution function says in that case that the result is unknown -- 'X'.

Check the log output of your synthesis tool as it should report these multiply driven nets as errors or possibly just warnings. (There is a time and place for multiply driven nets in designs that use tri-state signal assignments or ones that employ wired-and/or logic.)

Happily, the solution is simply to merge everything into a single process and try again. I suspect you will have additional work to do as the logical function of your design is not apparent to me in my cursory examination of it. (As a useful exercise, change all std_logic types to bit and re-analyze. The multiply driven nets stand out like a sore thumb.)

Here are some tips concerning the coding style you have employed:

  • Use the rising_edge() function rather than clk'event and clk='1'. While unusual, the later approach can lead to subtle simulation errors if the clk transitions to '1' from say 'X' or 'U' which might lead you to believe the circuit is working only to discover that the hardware behaves differently.

  • You want your state machine to be reset. So the Processo Ascensore should have either a synchronous or asynchronous reset signal clearing the state register.

  • You have several if statements that appear to be decrementing various signals. The if-elsif-elsif compound statement synthesizes to a priority encoder which will result in longer combinatorial paths and possibly slower timing. Always look for an opportunity to use a case statement to implement parallel logic.

  • With that said, what your VHDL really needs is to use unsigned type signals to implement the decrement arithmetic necessary for the various counters in your design. For example, the countPorta signal should be declared as unsigned(2 downto 0) and the clocked process that operates on it should simply specify countPorta <= countPorta - "001"; -- same for the other decrementing counters.

  • The third process incorrectly (but not illegally) specifies two distinct if clauses where only one is necessary. In fact, the second if clause always 'wins' as it comes later when evaluating the assignment to signal df.

Since you have not supplied a testbench after your original post, as requested by @user1155120, I can go no further. Good luck.

0
Amir_HK On

Most of the times, errors like this occur because of erroneous connection of ports in testbench, for to be sure about this, you can check the connection, but if you can't find any mistake, you can test your module without testbench and use force value and force clock But if it is still unknown, your mistake is in wave selection to view.

good luck