Controladores de señal múltiple VHDL

Estoy tratando de aprender buenas metodologías de diseño de vhdl. Estaba tratando de encontrar algunos consejos sobre múltiples controladores de señal. Lamentablemente sin éxito. Mi pregunta es si es buena idea tener señal con múltiples unidades (o lo evitaré casi siempre).

Mi problema: - Tengo algún módulo de transmisión. Me gustaría tener algún indicador (solo por ejemplo uno) que informe que hay un nuevo dato. Un proceso establece el indicador si hay nuevos datos disponibles, otro borra el indicador después de la lectura.

En este caso, tengo dos procesos que impulsan una señal resuelta. El problema que puedo ver aquí es la concurrencia. ¿Existe un buen patrón de desarrollo para un problema como este? ¿Debo evitar y nunca usar múltiples controladores de señal?

En general, nunca utilice varios controladores. Una forma en que puede implementar esto es usar una puerta OR para todas sus señales de conducción. Si alguna de las señales está activa, la salida se activa. Si necesita restablecer, necesitará más lógica para restablecer sus señales
Para ser correcto: no existen múltiples controladores en VHDL. En realidad, se trata de múltiples fuentes :).

Respuestas (2)

No puede tener varios controladores para una señal dada

Según su descripción, parece que está tratando de resolver algún tipo de apretón de manos entre sus dos procesos. Si bien puede haber una solución más elegante, sin haber visto su código, supongamos que realmente necesita un apretón de manos. Incluso si no lo necesita ahora, puede hacerlo más adelante.

Para ayudar en la discusión, modelaré el comportamiento usando dos componentes (o entidades) en lugar de procesos, para que el diagrama sea más claro.

Suponga que tiene una entidad que recibe datos y otra que procesa los datos. Suponga también que solo desea recibir datos nuevos mientras el procesador está inactivo (es decir, ha terminado de trabajar en el último conjunto de datos).

Para esto, necesitarás un apretón de manos. La primera entidad (llámela data_memory ) necesita saber cuándo está el data_processoridle y el data_processor necesita saber cuándo tiene la memoria data_rdy.

Esto se parece a tu publicación:

Me gustaría tener algún indicador (solo por ejemplo uno) que informe que hay un nuevo dato. Un proceso establece el indicador si hay nuevos datos disponibles, otro borra el indicador después de la lectura. [sic]

Aquí tenemos un indicador data_rdyque se establece cuando hay nuevos datos disponibles y se borra después de leerlos y procesarlos:

Diagrama RTL

Para la instancia de data_memory , podemos sincronizar los datos directamente desde data_inel data_processor siempre que la habilitación de escritura wrensea alta. La data_rdybandera le permite al procesador saber cuándo hay nuevos datos listos y en espera.

-- data_memory.vhd
library ieee;
use ieee.std_logic_1164.all;

entity data_memory is
    port ( data_in  : in  std_logic_vector (7 downto 0);
           wren     : in  std_logic;
           rdy_read : in  std_logic;
           clk      : in  std_logic;
           data_out : out std_logic_vector (7 downto 0);
           data_rdy : out std_logic );
end data_memory;

architecture Behavioral of data_memory is
begin
    process (clk)
    begin
        if (rising_edge(clk)) then
            if (wren = '1') then
                -- in practice, we would add a queue here
                data_out <= data_in;
            end if;
            data_rdy <= wren and rdy_read;
        end if;
    end process;
end Behavioral;

El procesador de datos luego usa los datos siempre que la data_rdyseñal sea alta:

-- data_processor.vhd
library ieee;
use ieee.std_logic_1164.all;

entity data_processor is
    port ( data_in  : in  std_logic_vector (7 downto 0);
           data_rdy : in  std_logic;
           clk      : in  std_logic;
           data_out : out std_logic_vector (7 downto 0);
           idle     : out std_logic );
end data_processor;

architecture Behavioral of data_processor is
    signal process_wait_cycle  : std_logic_vector (63 downto 0) := (others => '1');
begin
    process (clk)
    begin
        if (rising_edge(clk)) then
            if (data_rdy = '1') then
                -- in practice, we would actually do something with the data;
                -- here we'll just make a copy and send it out
                data_out <= data_in;
                process_wait_cycle <= (others => '0');
                idle <= '0';
            else
                process_wait_cycle <= process_wait_cycle(62 downto 0) & '1';
                idle <= process_wait_cycle(63);
            end if;
        end if;
    end process;
end Behavioral;

El process_wait_cycleregistro de desplazamiento se usa aquí solo como un medio para consumir algunos ciclos de reloj para simular un tiempo de procesamiento. Cuando se completa el procesamiento, la entidad establece el idleindicador en alto, que luego regresa a la entrada del bloque data_memory .

Finalmente, podemos unir estos dos en una instancia de nivel superior:

-- transmission.vhd
library ieee;
use ieee.std_logic_1164.all;

entity transmission is
    port ( data_in     : in  std_logic_vector (7 downto 0);
           wren        : in  std_logic;
           clk         : in  std_logic;
           data_out    : out std_logic_vector (7 downto 0);
           data_status : out std_logic );
end transmission;

architecture Behavioral of transmission is

-- Component data_memory
component data_memory is
port (
    data_in  : in  std_logic_vector (7 downto 0);
    wren     : in  std_logic;
    rdy_read : in  std_logic;
    clk      : in  std_logic;
    data_out : out std_logic_vector (7 downto 0);
    data_rdy : out std_logic );
end component;

-- Component data_processor
component data_processor is
port (
    data_in  : in  std_logic_vector (7 downto 0);
    data_rdy : in  std_logic;
    clk      : in  std_logic;
    data_out : out std_logic_vector (7 downto 0);
    idle     : out std_logic );
end component;

-- Signals
signal data_rdy        : std_logic := '0';
signal processor_ready : std_logic := '0';
signal data_from_mem   : std_logic_vector (7 downto 0) := X"00";

begin

    data_status <= data_rdy;

    -- data_memory instance
    data_memory_inst : data_memory
    port map (
        data_in  => data_in,
        wren     => wren,
        rdy_read => processor_ready,
        clk      => clk,
        data_out => data_from_mem,
        data_rdy => data_rdy );

    -- data_processor instance
    data_processor_inst : data_processor
    port map (
        data_in  => data_from_mem,
        data_rdy => data_rdy,
        clk      => clk,
        data_out => data_out,
        idle     => processor_ready );

end Behavioral;

Y simular:simulación

Aquí puede ver que los datos solo se usan cuando wren y idle es alto, lo que indica que el procesador está inactivo y que están ingresando nuevos datos.

En caso de que esté interesado en el archivo de simulación:

-- Transmission sim
library ieee;
use ieee.std_logic_1164.all;
use ieee.math_real.all;
use ieee.numeric_std.all;

entity transmission_sim is
--  Port ( );
end transmission_sim;

architecture Behavioral of transmission_sim is

component transmission is
port ( data_in     : in  std_logic_vector (7 downto 0);
       wren        : in  std_logic;
       clk         : in  std_logic;
       data_out    : out std_logic_vector (7 downto 0);
       data_status : out std_logic );
end component;

signal data_in     : std_logic_vector (7 downto 0) := X"AB";
signal wren        : std_logic := '0';
signal clk         : std_logic := '0';
signal data_out    : std_logic_vector (7 downto 0) := X"00";
signal data_status : std_logic := '0';

constant PERIOD : time := 10 ns;
constant DUTY   : real := 0.5;

begin

    uut : transmission
    port map (
        data_in     => data_in,
        wren        => wren,
        clk         => clk,
        data_out    => data_out,
        data_status => data_status );

    process
    begin
        loop
            clk <= '0';
            wait for (PERIOD - (PERIOD * DUTY));
            clk <= '1';
            wait for (PERIOD - (PERIOD * DUTY));
        end loop;
    end process;

    process
        variable seed1, seed2: positive;
        variable rand: real;
        variable range_of_rand : real := 255.0;
    begin
        wait for (PERIOD*10);
        wren <= '1';
        wait for (PERIOD*10);
        wren <= '0';
        wait for (PERIOD*10);
        uniform(seed1, seed2, rand);
        data_in <= std_logic_vector(to_unsigned(integer(rand*range_of_rand), data_in'length));
    end process;

end Behavioral;
¿Quieres decir BLUF o BLUF ? Estoy 99,9% seguro de que es lo último, pero tuve que buscarlo en Google.
@HarrySvensson Jaja. Por supuesto el segundo. La primera es nueva para mí. Usamos BLUF (línea inferior al frente) en muchos correos electrónicos en mi departamento. Las personas tienden a querer ir al grano de inmediato.

Sí, evite varios conductores.

Puede tener dos señales: una que sea alta para un reloj después de nuevos datos y otra que sea alta para un reloj después de la lectura. Entonces en un proceso puedes hacer

if rising_edge(CLK) then 
    if write_sig = '1' then
        flag <= '1';
    elsif read_sig = '1' then
        flag <= '0';
    end if;
end if;

Depende de usted decidir la prioridad de colocar o quitar la bandera, pero priorizar la colocación de la bandera parece tener más sentido.