Auf den ersten Blick würde man erwarten, dass sich der folgende VHDL-Quellcode wie ein Schieberegister verhält. In diesem q, im Laufe der Zeit wäre
"UUUU0", "UUU00", "UU000", "U0000", "00000", ....
aber stattdessen ist es immer U
nach fünf (oder mehr) aufeinanderfolgenden Taktzyklen.
Warum ist das?
Dieser Code ist eigentlich eine viel vereinfachte Version einer viel komplizierteren Simulation. Aber es zeigt die Symptome, die ich sehe.
Es zeigt dieses interessante und unerwartete Ergebnis während der Simulation sowohl unter ModelSim als auch unter ActiveHDL, ich habe keine anderen Simulatoren ausprobiert und würde (neben einer Erklärung der Ursache) gerne wissen, ob andere genauso handeln.
Um diese Frage richtig beantworten zu können, müssen Sie Folgendes verstehen:
&
.Was ich auch gefunden habe:
temp(0)<='0';
innerhalb des Prozesses verschoben wird, funktioniert es.Ich möchte wiederholen, dass dies eine sehr vereinfachte Version eines viel komplizierteren Designs (für eine Pipeline-CPU) ist, das so konfiguriert ist, dass es nur die unerwarteten Simulationsergebnisse zeigt. Die eigentlichen Signaltypen sind nur eine Vereinfachung. Aus diesem Grund müssen Sie Ihre Antworten mit dem Code in der Form so betrachten, wie sie sind.
Meine Vermutung ist, dass der Optimierer der VHDL-Simulations-Engine fälschlicherweise (oder vielleicht gemäß der 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 ausgepackte Schleife in eine Schleife platziere.
Ich gehe also davon aus, dass die Antwort auf diese Frage eher mit den Standards für die VHDL-Simulation der nicht expliziten VHDL-Syntax und der Art und Weise, wie VHDL-Simulations-Engines ihre Optimierungen durchführen, zu tun hat, als ob das angegebene Codebeispiel der beste Weg ist, etwas zu tun oder nicht.
Und nun zu dem 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;
Es hat damit zu tun, was formal zur Zeit der Ausarbeitung leicht ausgewertet werden kann, was als "lokal statischer Ausdruck" bezeichnet wird. Dies ist eine obskur aussehende Regel, aber sie verdient einige Überlegung - schließlich ergibt sie einen Sinn, und Ihr Simulator warnt Sie zu Recht, indem er nicht offensichtliche Ergebnisse generiert.
Kann jetzt temp(1)
zur Kompilierzeit (sogar früher als zur Ausarbeitungszeit) ausgewertet werden und einen Treiber auf Bit 1 von "temp" generieren.
Allerdings temp(i)
bedeutet das etwas mehr Arbeit für die Werkzeuge. Angesichts der trivialen Natur der Schleifengrenzen hier ( 1 bis 4 ) ist es für uns Menschen offensichtlich, dass temp(0) nicht gefahren werden kann und was Sie tun, ist sicher. Aber stellen Sie sich vor, die Grenzen wären Funktionen lower(foo) to upper(bar)
in einem Paket, das woanders deklariert wurde ... jetzt können Sie höchstens mit Sicherheit sagen, dass temp
es gesteuert wird - also ist der "lokal statische" Ausdruck temp
.
Und das bedeutet, dass der Prozess durch diese Regeln eingeschränkt wird, um alle zu steuern temp
, an welchem Punkt Sie mehrere Treiber haben temp(0)
- den Prozess, der (kein Anfangswert, dh 'u') und den externen antreibt temp(0) <= '0';
. Also lösen sich die beiden Treiber natürlich auf 'U' auf.
Die Alternative wäre eine "kleine Hacky-Regel" (Meinung), dass, wenn die Schleifengrenzen Konstanten wären, eine Sache tun, aber wenn sie als etwas anderes deklariert wurden, etwas anderes tun und so weiter ... desto mehr solche seltsamen kleinen Regeln es gibt, je komplexer die Sprache wird ... meiner Meinung nach keine bessere Lösung.
temp(0)<='Z'
innerhalb des Prozesses „repariert“ das Verhalten (wenn „reparieren“ das richtige Wort ist), vielleicht sollte es Maske oder Fudge sein …
Matt
David Tweed
temp(0)
da der Literalkonstante keine "Ereignisse" zugeordnet sind. Wenn Sie die Zuweisung in dieprocess
einfügen, wird eine Assoziation mit den Uhrereignissen erstellt, die dafür sorgen, dass sie funktioniert. Ich frage mich, ob das Hinzufügen einerafter
Klausel zur Aufgabe eine mögliche Problemumgehung wäre.