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?
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_rdy
que se establece cuando hay nuevos datos disponibles y se borra después de leerlos y procesarlos:
Para la instancia de data_memory , podemos sincronizar los datos directamente desde data_in
el data_processor siempre que la habilitación de escritura wren
sea alta. La data_rdy
bandera 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_rdy
señ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_cycle
registro 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 idle
indicador 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;
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;
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.
adam z
Paebbels