À première vue, vous vous attendez à ce que le code source VHDL ci-dessous se comporte comme un registre à décalage. Dans ce q, au fil du temps serait
"UUUU0", "UUU00", "UU000", "U0000", "00000", ....
mais c'est toujours U
après cinq (ou plus) cycles d'horloge consécutifs.
Pourquoi est-ce?
Ce code est en fait une version beaucoup plus simplifiée d'une simulation beaucoup plus compliquée. Mais cela démontre les symptômes que je vois.
Il présente ce résultat intéressant et inattendu lors de la simulation sous ModelSim et ActiveHDL, je n'ai pas essayé d'autres simulateurs et j'aimerais (deuxièmement pour une explication de la cause) savoir si d'autres agissent de la même manière.
Pour répondre correctement à cette question, vous devez comprendre que:
- Je sais que ce n'est pas la meilleure façon de mettre en place un registre à décalage
- Je sais que pour la synthèse RTL, cela devrait avoir une réinitialisation.
- Je sais qu'un tableau de std_logic est un std_logic_vector.
- Je sais que l'opérateur d'agrégation,
&
.
Ce que j'ai également trouvé:
- Si l'affectation
temp(0)<='0';
est déplacée à l'intérieur du processus, cela fonctionne. - Si la boucle est déroulée (voir le code commenté), cela fonctionne.
Je répéterai qu'il s'agit d'une version très simplifiée d'une conception beaucoup plus compliquée (pour un processeur pipeliné), configurée pour afficher uniquement les résultats de simulation inattendus. Les types de signaux réels ne sont qu'une simplification. Pour cette raison, vous devez considérer vos réponses avec le code dans le formulaire tel quel.
Je suppose que l'optimiseur du moteur de simulation VHDL ne prend pas la peine (ou peut-être selon les spécifications) d'exécuter les expressions à l'intérieur de la boucle car aucun signal extérieur ne change, bien que je puisse réfuter cela en plaçant la boucle non enveloppée dans une boucle.
Je m'attends donc à ce que la réponse à cette question soit davantage liée aux normes de simulation VHDL de la syntaxe VHDL inexplicite et à la façon dont les moteurs de simulation VHDL effectuent leurs optimisations, plutôt que si un exemple de code donné est la meilleure façon de faire quelque chose ou non.
Et maintenant, au code que je simule:
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;
Et le banc d'essai:
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;
la source
temp(0)
car aucun "événement" n'est associé à la constante littérale. Placer l'affectation à l'intérieur duprocess
crée une association avec les événements d'horloge qui le fait fonctionner. Je me demande si l'ajout d'uneafter
clause à la cession serait une solution de contournement potentielle.Réponses:
Il s'agit de ce qui peut être facilement évalué au moment de l'élaboration, formellement, de ce qu'on appelle une "expression localement statique". C'est une règle d'apparence obscure, mais elle mérite une réflexion - elle a finalement un sens, et votre simulateur est tout à fait correct pour vous alerter en générant des résultats non évidents.
Maintenant,
temp(1)
peut être évalué au moment de la compilation (même plus tôt que le temps d'élaboration) et il peut générer un pilote sur le bit 1 de "temp".Cependant, cela
temp(i)
implique un peu plus de travail pour les outils. Étant donné la nature triviale des limites de la boucle ici (1 à 4), il est évident pour nous, les humains, que temp (0) ne peut pas être piloté et ce que vous faites est sûr. Mais imaginez que les limites étaient des fonctionslower(foo) to upper(bar)
dans un package déclaré ailleurs ... maintenant, tout ce que vous pouvez dire avec certitude est qu'iltemp
est piloté - ainsi l'expression "localement statique" l'esttemp
.Et cela signifie que le processus est contraint par ces règles à tout piloter
temp
, auquel cas vous avez plusieurs pilotes surtemp(0)
- le pilotage du processus (pas de valeur initiale, c'est-à-dire «u») et l'externetemp(0) <= '0';
. Donc, naturellement, les deux pilotes se résolvent en «U».L'alternative serait une "petite règle hacky" (opinion) que si les limites de la boucle étaient des constantes, faites une chose, mais si elles étaient déclarées comme autre chose, faites autre chose, et ainsi de suite ... plus de petites règles bizarres il y en a, plus la langue devient complexe ... à mon avis, pas une meilleure solution.
la source