Automatisierter Multiplexer in vhdl

Ich möchte einen MUXer machen, der zwischen 2 Signalen umschaltet, sagen wir A und B. Signal A und B erzeugen auch beide Interrupts. Der MUXer zählt die Interrupts und zum Beispiel nach n-Interrupts von A wird der Ausgang der von B. Wenn B m-Interrupts erzeugt, schaltet der Ausgang zurück zu A.

Im zugrunde liegenden Code warte ich auf 3 Impulse des A-Interrupts, währenddessen ist der Mux-Ausgang A. Danach warte ich auf 5 Impulse des B-Interrupts, während der Mux-Ausgang zu B wird. Der gesamte Zyklus wird dann wiederholt.

Ich implementiere dies mit einem 3-Prozess-FSM, wie hier erklärt: http://www.csit-sun.pub.ro/courses/Masterat/Xilinx%20Synthesis%20Technology/toolbox.xilinx.com/docsan/xilinx4/data/ docs/xst/hdlcode15.html

Kann jemand erklären, warum es nicht richtig funktioniert? Der vhdl-Code:

entity FSM_MUX is
    Port ( CLK : in STD_LOGIC;
           RST : in STD_LOGIC;
           A: in STD_LOGIC;
           A_INT : in STD_LOGIC;
           B: in STD_LOGIC;
           B_INT : in STD_LOGIC;
           START : in STD_LOGIC;
           MUX_OUT : out STD_LOGIC);
end FSM_MUX;

architecture Behavioral of FSM_MUX is

type state is (iddle,state_A,state_B) ;
signal old_state : state ;
signal new_state : state ;

begin
process(CLK)
    begin   
        if (CLK' event and CLK = '1') then
            if RST = '0' or START = '0' then
                old_state <= iddle ;
            else
                old_state <= new_state;
            end if;
        end if;
end process;


process (old_state,A_INT,B_INT)
    variable counter : integer range 0 to ((2**16)-1):=0;
    begin
        case old_state is
            when iddle          =>          if  A_INT = '1' then
                                                new_state <= state_A;
                                            else
                                                new_state <= iddle;
                                            end if;

            when state_A       =>          if A_INT = '1' then
                                                if counter < 3  then 
                                                    counter := counter + 1;
                                                    new_state <= state_A;
                                                else
                                                    counter := 0;
                                                    new_state <= state_B;
                                                end if;
                                            end if;

            when state_B       =>          if  B_INT = '1' then
                                                if counter < 5  then 
                                                    counter := counter + 1;
                                                    new_state <= state_B;
                                                else
                                                    counter := 0;
                                                    new_state <= state_A;
                                                end if;
                                            end if;

        end case;
end process;

process(old_state)     
begin
    case old_state is
        when iddle    =>        MUX <='0';
        when state_A =>         MUX <= A;
        when state_B =>         MUX <= B;       
   end case;

end process;
end Behavioral;

Vielen Dank im Voraus!

Es unterliegt höchstwahrscheinlich einigen der üblichen Mängel eines 2-Prozess-SM. Überprüfen Sie es auf Sensitivitätslistenfehler, Latches oder Zähler im asynchronen Prozess usw. Oder schreiben Sie es einfach in die einfachere, kleinere und zuverlässigere Einzelprozessform um.
Ich habe tatsächlich darauf geantwortet, weil der Code "Fehler" für mich offensichtlich war. Aber geben Sie beim nächsten Mal bitte eine Testbench an, die das fehlerhafte Verhalten zeigt. Und beschreiben Sie dann in der Frage das erwartete Verhalten.

Antworten (1)

Die Variable counterist eigentlich ein Register, also müssen Sie sie im ersten getakteten Prozess beschreiben. Sie können es im zweiten Prozess nicht beschreiben, da Sie weniger Kontrolle darüber haben, wie oft dieser Prozess während desselben Taktzyklus fortgesetzt wird . Der Prozess wird fortgesetzt, wenn sich eines der Signale in der Prozesssensitivitätsliste ändert. Ich bevorzuge auch Signale anstelle von Variablen, da Sie in den meisten Simulatoren zum Debuggen nur Signale zur Wellenform hinzufügen können.

Um ein counterRegister im ersten (getakteten) Prozess vom zweiten Prozess aus zu steuern, benötigen Sie zwei Steuersignale: counter_rstwann der Zähler zurückgesetzt werden soll und counter_incwann der Zähler inkrementiert werden soll. Der Zähler im ersten Prozess lässt sich dann beschreiben mit:

    if (CLK' event and CLK = '1') then
        if counter_rst = '1' then   -- you may add RST and/or START here
            counter <= 0;
        elsif counter_inc = '1' then
            counter <= counter + 1;
        end if;
    end if;

RSTSie können oder STARTunter der ersten Bedingung hinzufügen , um Ihren Anforderungen gerecht zu werden.

counter_inc <= '1';Zum Beispiel wird der Zähler jetzt erhöht, wenn Sie im zweiten Vorgang zuweisen . Dies ersetzt die Zuweisung von counter := counter + 1;in Ihrem aktuellen Code. Wenn kein Inkrement benötigt wird, müssen Sie zuweisen counter_inc <= '0'. Dies wird erreicht, indem zu Beginn des Prozesses eine Standardzuweisung vorgenommen wird. Das Steuersignal counter_rstwird auf ähnliche Weise behandelt. Der countermuss der Vertraulichkeitsliste des zweiten Prozesses hinzugefügt werden, da Sie hier kombinatorische Logik wünschen.

Sie müssen auch die Gegenkontrollen reparieren. Wenn Sie 3 Impulse zählen möchten, müssen Sie von 0 bis 2 zählen.

Ihr Code benötigt auch eine Standardzuweisung für new_state, da Sie im zweiten Prozess nicht in jedem Zweig einen neuen Wert zugewiesen haben. Im letzten Prozess muss es MUX_OUTanstelle von MUXauch lauten Aund Bmuss der Prozess-Sensitivitätsliste hinzugefügt werden. Sonst bekommt man einen Riegel.

Dies ist der gesamte feste Code:

library ieee;
use ieee.std_logic_1164.all;

entity FSM_MUX is
    Port ( CLK : in STD_LOGIC;
           RST : in STD_LOGIC;
           A: in STD_LOGIC;
           A_INT : in STD_LOGIC;
           B: in STD_LOGIC;
           B_INT : in STD_LOGIC;
           START : in STD_LOGIC;
           MUX_OUT : out STD_LOGIC);
end FSM_MUX;

architecture Behavioral of FSM_MUX is

    type state is (iddle,state_A,state_B) ;
    signal old_state : state ;
    signal new_state : state ;
    signal counter : integer range 0 to ((2**16)-1) := 0;
    signal counter_inc : std_logic;         -- increment counter
    signal counter_rst : std_logic;         -- reset counter

begin
    process(CLK)
    begin   
        if (CLK' event and CLK = '1') then
            if RST = '0' or START = '0' then
                old_state <= iddle;
            else
                old_state <= new_state;
            end if;

            -- counter register
            if counter_rst = '1' then   -- you may add RST and/or START here
                counter <= 0;
            elsif counter_inc = '1' then
                counter <= counter + 1;
            end if;
        end if;
    end process;

    process (old_state, A_INT, B_INT, counter)  -- added counter
    begin
        counter_inc <= '0';             -- default assignment ...
        counter_rst <= '0';             -- ... may be overwritten below
        new_state   <= old_state;

        case old_state is
            when iddle =>
                if A_INT = '1' then
                    new_state <= state_A;
                else
                    new_state <= iddle;
                end if;

            when state_A =>
                if A_INT = '1' then
                    if counter < 2 then      -- count from 0 to 2 for 3 pulses
                        counter_inc <= '1';  -- increment counter
                        new_state <= state_A;
                    else
                        counter_rst <= '1';  -- reset counter
                        new_state <= state_B;
                    end if;
                end if;

            when state_B =>
                if B_INT = '1' then
                    if counter < 4 then      -- count from 0 to 4 for 5 pulses
                        counter_inc <= '1';  -- increment counter
                        new_state <= state_B;
                    else
                        counter_rst <= '1';  -- reset counter
                        new_state <= state_A;
                    end if;
                end if;
        end case;
    end process;

    process(old_state, A, B)            -- added A and B 
    begin
        case old_state is
            when iddle   => MUX_OUT <= '0';  -- MUX_OUT instead of MUX !
            when state_A => MUX_OUT <= A;
            when state_B => MUX_OUT <= B;
        end case;

    end process;
end Behavioral;

Das war mein Prüfstand:

library ieee;
use ieee.std_logic_1164.all;

entity FSM_MUX_tb is
end FSM_MUX_tb;

architecture sim of FSM_MUX_tb is

    signal CLK     : STD_LOGIC := '1';
    signal RST     : STD_LOGIC;
    signal A       : STD_LOGIC;
    signal A_INT   : STD_LOGIC;
    signal B       : STD_LOGIC;
    signal B_INT   : STD_LOGIC;
    signal START   : STD_LOGIC;
    signal MUX_OUT : STD_LOGIC;

begin  -- sim

    DUT: entity work.FSM_MUX
        port map (
            CLK     => CLK,
            RST     => RST,
            A       => A,
            A_INT   => A_INT,
            B       => B,
            B_INT   => B_INT,
            START   => START,
            MUX_OUT => MUX_OUT);

  -- clock generation
  CLK <= not CLK after 10 ns;

  -- waveform generation
  WaveGen_Proc: process
  begin
      RST <= '1';                       -- low-active, optional
      START <= '1';

      A <= '0';
      B <= '1';
      A_INT <= '0';
      B_INT <= '0';

      -- leave IDDLE state
      wait until rising_edge(CLK);
      A_INT <= '1';
      wait until rising_edge(CLK);
      A_INT <= '0';

      -- just some waiting
      wait until rising_edge(CLK);
      wait until rising_edge(CLK);

      -- 3 A_INT pulses to leave STATE_A
      for i in 1 to 3 loop
          wait until rising_edge(CLK);
          A_INT <= '1';
          wait until rising_edge(CLK);
          A_INT <= '0';
      end loop;  -- i

      -- 5 B_INT pulses to leave STATE_B
      for i in 1 to 5 loop
          wait until rising_edge(CLK);
          B_INT <= '1';
          wait until rising_edge(CLK);
          B_INT <= '0';
      end loop;  -- i

      wait;
  end process WaveGen_Proc;
end sim;

Und das ist die Simulationsausgabe:

Simulationsausgabe

Vielen Dank für die Hilfe! Nicht nur für Ihre Bemühungen, die richtige Lösung bereitzustellen, sondern auch, um das Warum und Wie genau zu erklären. Ich habe alles mit der Sensibilitätsliste versucht, obwohl ich die Standardzuweisung von new_state vergessen habe. Dass der Schalter eine Kasse war und so, wusste ich nicht. Ich werde versuchen, einige direkte "Übersetzungen" von vhdl in Hardware im www zu finden, es scheint, dass mein Wissen etwas poliert werden muss. Danke noch einmal!