0

我对始终发出的 vhdl 实体的输出有疑问U。我查看了各种论坛,但找不到解决方案。

该项目是一个 5 层的电梯,必须等待 5 秒才能关上门,10 秒才能到达下一个到达目标的飞机。使用 Logisim (v 2.13.22) 和 ghdl (v 0.29.1)。

有谁知道问题可能是什么?提前致谢

项目主电路

vhdl 模拟器日志

这是我制作的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;
4

2 回答 2

0

大多数情况下,出现这样的错误是因为testbench中的端口连接错误,为了确定这一点,你可以检查连接,但如果你找不到任何错误,你可以在没有testbench的情况下测试你的模块并使用力值和力时钟 但如果还是未知,你的错误是在波形选择查看。

祝你好运

于 2018-01-28T11:00:08.227 回答
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'总是在两个值之间的竞争中获胜。所以,无论在第三个过程中驱动什么,第四个过程中未初始化的信号都会做出贡献'U'并决定信号状态。(至少在状态机达到实际将已知值驱动到 的状态之前upEngine)。

您可能已经注意到在您的模拟中发出信号ledUp并且ledDown'X'第一个时钟上升沿之后。那是因为它们都是多重驱动的——但是一个驱动器贡献'1'了另一个驱动器'0'。在这种情况下,解析函数表示结果未知—— 'X'

检查综合工具的日志输出,因为它应该将这些多重驱动网络报告为错误或可能只是警告。(在使用三态信号分配或采用有线和/或逻辑的设计中,多重驱动网络是有时间和地点的。)

令人高兴的是,解决方案只是将所有内容合并到一个进程中,然后重试。我怀疑你还有额外的工作要做,因为在我粗略的检查中,你的设计的逻辑功能对我来说并不明显。(作为一个有用的练习,将所有std_logic类型更改为bit并重新分析。多重驱动的网络就像拇指酸痛一样突出。)

以下是有关您采用的编码风格的一些提示:

  • 使用rising_edge()函数而不是clk'event and clk='1'. '1'虽然不寻常,但如果 clk 转换为from say'X''U'可能导致您相信电路工作时发现硬件行为不同,则后一种方法可能会导致细微的仿真错误。

  • 您希望重置您的状态机。所以Processo Ascensore应该有一个同步或异步复位信号来清除状态寄存器。

  • 您有几条if语句似乎在减少各种信号。- if-复合语句综合到优先级编码器elsifelsif这将导致更长的组合路径和可能更慢的时序。总是寻找机会使用case语句来实现并行逻辑。

  • 话虽如此,您的 VHDL 真正需要的是使用unsigned类型信号来实现设计中各种计数器所需的递减算法。例如,countPorta 信号应声明为 unsigned(2 downto 0),并且对其进行操作的时钟进程应简单地指定countPorta <= countPorta - "001";-- 与其他递减计数器相同。

  • 第三个process错误(但并非非法)指定了两个不同的if子句,其中只有一个是必要的。事实上,第二个if子句总是“获胜”,因为它在评估对 signal 的赋值时会出现df

由于您没有按照@user1155120 的要求在原始帖子之后提供测试平台,因此我不能再进一步了。祝你好运。

于 2018-02-23T05:19:59.177 回答