A prima vista ti aspetteresti che il codice sorgente VHDL di seguito si comporti come un registro a scorrimento. In quel q, col tempo sarebbe
"UUUU0", "UUU00", "UU000", "U0000", "00000", ....
ma invece è sempre U
dopo cinque (o più) cicli di clock consecutivi.
Perchè è questo?
Questo codice è in realtà una versione molto semplificata di una simulazione molto più complicata. Ma dimostra i sintomi che vedo.
Presenta questo risultato interessante e inaspettato durante la simulazione sia con ModelSim che con ActiveHDL, non ho provato altri simulatori e (in secondo luogo per una spiegazione della causa) mi piacerebbe sapere se altri agiscono allo stesso modo.
Per rispondere correttamente a questa domanda devi capire che:
- So che questo non è il modo migliore per implementare un registro a turni
- So che per la sintesi RTL questo dovrebbe avere un reset.
- So che un array di std_logic è uno std_logic_vector.
- So che l'operatore di aggregazione,
&
.
Quello che ho trovato anche:
- Se l'assegnazione
temp(0)<='0';
viene spostata all'interno del processo, funziona. - Se il ciclo non è scartato (vedi codice commentato), funziona.
Ribadirò che questa è una versione molto semplificata di un design molto più complicato (per una CPU pipeline), configurata per mostrare puramente i risultati di simulazione imprevisti. I tipi di segnale effettivi sono solo una semplificazione. Per questo motivo devi considerare le tue risposte con il codice nel modulo così com'è.
La mia ipotesi è che l'ottimizzatore del motore di simulazione VHDL stia erroneamente (o forse secondo le specifiche) a non preoccuparsi di eseguire le espressioni all'interno del loop poiché nessun segnale esterno cambia, anche se posso confutare ciò inserendo il loop non imballato in un loop.
Quindi mi aspetto che la risposta a questa domanda abbia più a che fare con gli standard per la simulazione VHDL della sintassi VHDL esplicita e con il modo in cui i motori di simulazione VHDL eseguono le loro ottimizzazioni, piuttosto che se un esempio di codice sia il modo migliore per fare qualcosa o meno.
E ora al codice che sto 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 il banco prova:
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)
perché non ci sono "eventi" associati alla costante letterale. Inserendo il compito all'interno di process
crea un'associazione con gli eventi di clock che lo fa funzionare. Mi chiedo se l'aggiunta di una after
clausola al compito sarebbe una potenziale soluzione alternativa.