2017-08-29 123 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的要求,我不能走的更远。祝你好运。