Auf den ersten Blick würde man erwarten, dass sich der folgende VHDL-Quellcode wie ein Schieberegister verhält. In diesem q wäre im Laufe der Zeit
"UUUU0", "UUU00", "UU000", "U0000", "00000", ....
Stattdessen ist es immer U
nach fünf (oder mehr) aufeinanderfolgenden Taktzyklen.
Warum ist das?
Dieser Code ist eigentlich eine stark vereinfachte Version einer weitaus komplizierteren Simulation. Aber es zeigt die Symptome, die ich sehe.
Es zeigt dieses interessante und unerwartete Ergebnis während der Simulation unter ModelSim und ActiveHDL. Ich habe keine anderen Simulatoren ausprobiert und möchte (zweitens zur Erklärung der Ursache) wissen, ob andere auf die gleiche Weise handeln.
Um diese Frage richtig zu beantworten, müssen Sie Folgendes verstehen:
- Ich weiß, dass dies nicht der beste Weg ist, ein Schieberegister zu implementieren
- Ich weiß, dass dies für die RTL-Synthese zurückgesetzt werden sollte.
- Ich weiß, dass ein Array von std_logic ein std_logic_vector ist.
- Ich kenne den Aggregationsoperator
&
.
Was ich auch gefunden habe:
- Wenn die Zuordnung
temp(0)<='0';
innerhalb des Prozesses verschoben wird, funktioniert sie. - Wenn die Schleife entpackt ist (siehe kommentierten Code), funktioniert sie.
Ich werde noch einmal betonen, dass dies eine sehr vereinfachte Version eines viel komplizierteren Designs (für eine Pipeline-CPU) ist, das so konfiguriert ist, dass nur die unerwarteten Simulationsergebnisse angezeigt werden. Die tatsächlichen Signaltypen sind nur eine Vereinfachung. Aus diesem Grund müssen Sie Ihre Antworten mit dem Code im Formular so wie er ist betrachten.
Ich vermute, dass der Optimierer der VHDL-Simulations-Engine fälschlicherweise (oder möglicherweise gemäß Spezifikation) nicht die Mühe macht, die Ausdrücke innerhalb der Schleife auszuführen, da sich keine Signale außerhalb ändern, obwohl ich dies widerlegen kann, indem ich die nicht verpackte Schleife in eine Schleife setze.
Ich gehe daher davon aus, dass die Antwort auf diese Frage eher mit den Standards für die VHDL-Simulation unerklärlicher VHDL-Syntax und der Art und Weise zu tun hat, wie VHDL-Simulationsmodule ihre Optimierungen vornehmen, als ob ein gegebenes Codebeispiel der beste Weg ist, etwas zu tun oder nicht.
Und nun zum Code, den ich simuliere:
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;
Und der Prüfstand:
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;
quelle
temp(0)
keine "Ereignisse" zugeordnet sind. Durch das Einfügen der Zuweisung inprocess
wird eine Zuordnung zu den Uhrereignissen erstellt, die dazu führen, dass sie funktioniert. Ich frage mich, ob das Hinzufügen einerafter
Klausel zur Zuweisung eine mögliche Problemumgehung wäre.Antworten:
Es hat mit dem zu tun, was zur Ausarbeitungszeit formal leicht ausgewertet werden kann, was als "lokal statischer Ausdruck" bezeichnet wird. Dies ist eine obskur aussehende Regel, aber sie verdient einige Überlegungen - schließlich macht sie Sinn, und Ihr Simulator warnt Sie ganz korrekt, indem er nicht offensichtliche Ergebnisse generiert.
Nun
temp(1)
kann bei der Kompilierung ausgewertet (sogar früher als Ausarbeitung Zeit) und es kann einen Fahrer auf Bit 1 von „temp“ erzeugen.Dies
temp(i)
erfordert jedoch etwas mehr Arbeit für die Werkzeuge. Angesichts der Trivialität der Schleifengrenzen hier (1 bis 4) ist es für uns Menschen offensichtlich, dass Temp (0) nicht gefahren werden kann und was Sie tun, sicher ist. Aber stellen Sie sich vor, die Grenzen wären Funktionenlower(foo) to upper(bar)
in einem Paket, das woanders deklariert wurde ... jetzt können Sie mit Sicherheit nur sagen, dass sietemp
gesteuert werden - also ist der "lokal statische" Ausdrucktemp
.Und das bedeutet, dass der Prozess durch diese Regeln eingeschränkt wird, um alle zu steuern
temp
. An diesem Punkt haben Sie mehrere Treiber aktivierttemp(0)
- den Prozess, der fährt (kein Anfangswert, dh 'u') und den externentemp(0) <= '0';
. Natürlich lösen sich die beiden Treiber in 'U' auf.Die Alternative wäre eine "hackige kleine Regel" (Meinung): Wenn die Schleifengrenzen Konstanten wären, tun Sie eine Sache, aber wenn sie als etwas anderes deklariert wurden, tun Sie etwas anderes und so weiter ... umso mehr solche seltsamen kleinen Regeln Je komplexer die Sprache wird ... meiner Meinung nach keine bessere Lösung.
quelle