À primeira vista, você esperaria que o código fonte VHDL abaixo se comportasse como um registro de turno. Nesse q, com o tempo seria
"UUUU0", "UUU00", "UU000", "U0000", "00000", ....
mas, em vez disso, é sempre U
depois de cinco (ou mais) ciclos de relógio consecutivos.
Por que é isso?
Este código é na verdade uma versão muito simplificada de uma simulação muito mais complicada. Mas demonstra os sintomas que vejo.
Ele exibe esse resultado interessante e inesperado durante a simulação, tanto no ModelSim quanto no ActiveHDL. Não tentei outros simuladores e gostaria (em segundo lugar de uma explicação da causa) de saber se outros agem da mesma maneira.
Para responder a essa pergunta corretamente, você deve entender que:
- Sei que essa não é a melhor maneira de implementar um registro de turno
- Eu sei que para síntese RTL isso deve ter uma redefinição.
- Eu sei que uma matriz de std_logic é um std_logic_vector.
- Eu sei do operador de agregação
&
,.
O que eu também encontrei:
- Se a atribuição
temp(0)<='0';
for movida dentro do processo, ela funcionará. - Se o loop estiver desembrulhado (consulte o código comentado), ele funcionará.
Reiterarei que esta é uma versão muito simplificada de um design muito mais complicado (para uma CPU em pipeline), configurada para mostrar puramente os resultados inesperados da simulação. Os tipos de sinal reais são apenas uma simplificação. Por esse motivo, você deve considerar suas respostas com o código no formulário como está.
Meu palpite é que o otimizador do mecanismo de simulação VHDL, por engano (ou talvez de acordo com a especificação), não se incomoda em executar as expressões dentro do loop, pois nenhum sinal está fora da mudança, embora eu possa refutar isso colocando o loop não empacotado em um loop.
Portanto, espero que a resposta a esta pergunta tenha mais a ver com os padrões para simulação VHDL da sintaxe inexplicável VHDL e como os mecanismos de simulação VHDL fazem suas otimizações, em vez de se um exemplo de código é a melhor maneira de fazer algo ou não.
E agora para o código que estou 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;
E o banco de ensaio:
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 não há "eventos" associados à constante literal. Colocar a atribuição dentro de process
cria uma associação com os eventos do relógio que fazem com que ela funcione. Gostaria de saber se adicionar uma after
cláusula à atribuição seria uma solução potencial.