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
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;
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
andcurrent_s
are not assigned in a single process. They are driven in both the third and fourthprocess
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):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 ontoupEngine
).You might have noticed in your simulation that signals
ledUp
andledDown
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 tobit
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 thanclk'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. Theif
-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 acase
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 specifycountPorta <= countPorta - "001";
-- same for the other decrementing counters.The third
process
incorrectly (but not illegally) specifies two distinctif
clauses where only one is necessary. In fact, the secondif
clause always 'wins' as it comes later when evaluating the assignment to signaldf
.Since you have not supplied a testbench after your original post, as requested by @user1155120, I can go no further. Good luck.