Multiplexor automatizado en vhdl

1

Me gustaría hacer un MUXer que cambie entre 2 señales, digamos A y B. Las señales A y B también generan ambas interrupciones. El MUXer cuenta las interrupciones y, por ejemplo, después de n-interrupciones de A, la salida se convertirá en la de B. Si B genera m-interrupciones, la salida cambia de nuevo a A.

En el código subyacente, espero 3 pulsos de la interrupción A, durante este tiempo la salida del mux es A. Después de eso espero 5 pulsos de la interrupción B mientras que la salida del mux se convierte en B. Luego se repite todo el ciclo. / p>

Estoy implementando esto con un FSM de 3 procesos como se explica aquí: enlace

¿Puede alguien explicar por qué no funciona correctamente? El código vhdl:

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;

Gracias de antemano!

    
pregunta user3488736

1 respuesta

2

La variable counter es en realidad un registro, por lo que debe describirlo en el primer proceso que está cronometrado. No puede describirlo en el segundo proceso, porque tiene menos control sobre la frecuencia con la que este proceso se reanuda durante el ciclo de reloj mismo . El proceso se reanuda cada vez que cambia una de las señales en la lista de sensibilidad del proceso. También prefiero señales en lugar de variables porque en la mayoría de los simuladores solo se pueden agregar señales a la forma de onda para la depuración.

Para controlar un registro counter en el primer proceso (cronometrado) del segundo proceso, necesita dos señales de control: counter_rst cuando se debe restablecer el contador, y counter_inc cuando debe incrementarse el contador. El contador en el primer proceso se puede describir con:

    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;

Puede agregar RST o START en la primera condición para satisfacer sus necesidades.

Por ejemplo, el contador ahora se incrementa cuando asigna counter_inc <= '1'; en el segundo proceso. Esto reemplaza la asignación de counter := counter + 1; en su código actual. Si no se necesita ningún incremento, entonces debe asignar counter_inc <= '0' . Esto se logra al hacer una asignación predeterminada al inicio del proceso. La señal de control counter_rst se maneja de manera similar. El counter debe agregarse a la lista de sensibilidad del segundo proceso, porque aquí quiere lógica combinatoria.

También tienes que arreglar las comprobaciones del contador. Si desea contar 3 pulsos, debe contar de 0 a 2.

Su código también necesita una asignación predeterminada para new_state , porque no asignó un nuevo valor en cada rama en el segundo proceso. En el último proceso, debe leer MUX_OUT en lugar de MUX , también se deben agregar A y B a la lista de sensibilidad del proceso. De lo contrario obtienes un pestillo.

Este es el código fijo completo:

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;

Este fue mi banco de pruebas:

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;

Y esta es la salida de simulación:

    
respondido por el Martin Zabel

Lea otras preguntas en las etiquetas