A primera vista, esperaría que el código fuente VHDL a continuación se comportara como un registro de desplazamiento. En ese q, con el tiempo sería
"UUUU0", "UUU00", "UU000", "U0000", "00000", ....
pero en su lugar siempre es U
después de cinco (o más) ciclos de reloj consecutivos.
¿Por qué es esto?
Este código es en realidad una versión mucho más simplificada de una simulación mucho más complicada. Pero demuestra los síntomas que veo.
Exhibe este resultado interesante e inesperado durante la simulación tanto con ModelSim como con ActiveHDL, no he probado otros simuladores y (en segundo lugar, una explicación de la causa) me gustaría saber si otros actúan de la misma manera.
Para responder esta pregunta correctamente, debe comprender que:
- Sé que esta no es la mejor manera de implementar un registro de desplazamiento
- Sé que para la síntesis RTL esto debería tener un reinicio.
- Sé que una matriz de std_logic es un std_logic_vector.
- No conozco el operador de agregación,
&
.
Lo que también he encontrado:
- Si la asignación
temp(0)<='0';
se mueve dentro del proceso, funciona. - Si el bucle se desenvuelve (ver código comentado), funciona.
Reitero que esta es una versión muy simplificada de un diseño mucho más complicado (para una CPU canalizada), configurada para mostrar puramente los resultados inesperados de la simulación. Los tipos de señal reales son solo una simplificación. Por esta razón, debe considerar sus respuestas con el código en el formulario tal como está.
Supongo que el optimizador del motor de simulación VHDL no se molesta por error (o tal vez según las especificaciones) en ejecutar las expresiones dentro del bucle ya que no hay señales fuera del cambio, aunque puedo refutar esto colocando el bucle sin envolver en un bucle.
Así que espero que la respuesta a esta pregunta tenga más que ver con los estándares para la simulación VHDL de la sintaxis VHDL no explícita y cómo los motores de simulación VHDL hacen sus optimizaciones, en lugar de si el ejemplo de código dado es la mejor manera de hacer algo o no.
Y ahora al código que estoy simulando:
library ieee;
use ieee.std_logic_1164.all;
entity test_simple is
port (
clk : in std_logic;
q : out std_logic
);
end entity;
architecture example of test_simple is
type t_temp is array(4 downto 0) of std_logic;
signal temp : t_temp;
begin
temp(0) <= '0';
p : process (clk)
begin
if rising_edge(clk) then
for i in 1 to 4 loop
temp(i) <= temp(i - 1);
end loop;
--temp(1) <= temp(0);
--temp(2) <= temp(1);
--temp(3) <= temp(2);
--temp(4) <= temp(3);
end if;
end process p;
q <= temp(4);
end architecture;
Y el banco de pruebas:
library ieee;
use ieee.std_logic_1164.all;
entity Bench is
end entity;
architecture tb of bench is
component test_simple is
port (
clk : in std_logic;
q : out std_logic
);
end component;
signal clk:std_logic:='0';
signal q:std_logic;
signal rst:std_logic;
constant freq:real:=100.0e3;
begin
clk<=not clk after 0.5 sec / freq;
TB:process
begin
rst<='1';
wait for 10 us;
rst<='0';
wait for 100 us;
wait;
end process;
--Note: rst is not connected
UUT:test_simple port map (clk=>clk,q=>q) ;
end architecture;
temp(0)
porque no hay "eventos" asociados con la constante literal. Poner la asignación dentro de process
crea una asociación con los eventos del reloj que hace que funcione. Me pregunto si agregar una after
cláusula a la asignación sería una posible solución alternativa.