2017-08-29 119 views
0

我總是發送出去的vhdl實體的輸出有問題U。 我看了各種論壇,但我找不到解決方案。(VHDL)在vhdl實體中輸出的問題

該項目是一個5層的電梯,必須等待5秒關閉門,10秒鐘才能到達下一層目標。 使用Logisim(v 2.13.22)和ghdl(v 0.29.1)。

有沒有人有任何想法可能是什麼問題?在此先感謝

Main circuit of the project

vhdl simulator log

這裏的VHDL代碼我做了。

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

有一個[最小,完整和可驗證的例子](https://stackoverflow.com/help/mcve)這個概念,當請求代碼問題的幫助。你的問題不提供MCVe(提示測試臺不存在)。 – user1155120

+1

您的代碼不會分析哪個表明它在(尚未看到的)測試平臺詳細闡述時未綁定。那肯定會導致'U'。 'then then next_s <= s0;'應該移除額外的'then'。 – user1155120

回答

0

大部分的時間,像這樣的錯誤,因爲在測試平臺端口的錯誤連接的發生,可以肯定這一點,你可以檢查連接,但如果你不能找到任何錯誤,你可以在沒有測試平臺的情況下測試你的模塊並使用強制值和強制時鐘但是如果它仍然未知,你的錯誤是在波形選擇中查看。

好運

0

我不知道你在哪裏,在這個設計,但我希望你在你自己取得了一些進展,因爲發佈。

現在,到你的問題的核心。信號upEngine,downEngine,...,doorCloseEnginecurrent_s未分配在單個過程中。它們在第三個和第四個process報表中都被驅動,因此構成了多重驅動的網的情況

在您的模擬器中,查找將報告任何給定信號的驅動程序的命令。下面是我在Vivado請參閱upEngine信號是什麼(你的行號可能不完全匹配 - 我調整了代碼):

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 

這有點微妙。當有多個驅動程序時,VHDL使用解析函數來決定該做什麼。在這種情況下,由於信號類型爲std_logic,std_logic_1164庫指定解析函數,並且它說'U'總是在兩個值之間的比賽中獲勝。因此,無論在第三個過程中驅動什麼,第4個過程中的未初始化信號將貢獻'U'並確定信號狀態。 (至少直到狀態機達到一個實際將已知值驅動到upEngine的狀態)。

您可能在仿真中注意到信號ledUpledDown在第一個上升時鐘沿之後爲'X'。這是因爲他們都是多元驅動的 - 不過一位車手貢獻了'1',另一位車手貢獻了'0'。解析函數在這種情況下表示結果是未知的 - 'X'

檢查綜合工具的日誌輸出,因爲它應報告這些乘法驅動的網絡錯誤或可能只是警告。 (在使用三態信號分配的設計或者採用有線和/或邏輯分配的設計中,有時間和地點用於乘法驅動的網絡。)

令人高興的是,解決方案只是簡單地將所有內容合併到一個進程中,然後重試。我懷疑你會有額外的工作要做,因爲我粗略地檢查你的設計的邏輯功能對我來說並不明顯。 (作爲一個有益的做法,改變所有std_logic類型bit和重新分析多重驅動網脫穎而出像突兀。)

以下是關於你所使用的編碼風格的一些技巧:

  • 使用rising_edge()函數而不是clk'event and clk='1'。雖然不常見,但如果clk從'X''U'轉換到'1',則後面的方法可能會導致細微的模擬錯誤,這可能會導致您相信電路僅用於發現硬件的行爲不同。

  • 你希望你的狀態機被重置。所以Processo Ascensore應該有一個同步或異步復位信號清除狀態寄存器。

  • 您有幾個if語句看起來是遞減各種信號。 if - elsif - elsif - elsif複合語句將合成到優先級編碼器,這將導致更長的組合路徑和可能更慢的時序。總是尋找機會使用case語句來實現並行邏輯。這就是說,你的VHDL真正需要的是使用unsigned類型的信號來實現設計中不同計數器所需的遞減算術。例如,countPorta信號應該聲明爲無符號(2 downto 0),並且對其進行操作的時鐘進程應該簡單地指定爲countPorta <= countPorta - "001"; - 對於其他遞減計數器也是如此。

  • 第三個process不正確(但不是非法)指定了兩個不同的if子句,其中只有一個是必要的。實際上,第二個if子句在評估賦值爲信號df時總是「勝利」。

既然你已經不是你原來的職位之後提供一個測試平臺,通過@ user1155120的要求,我不能走的更遠。祝你好運。